反应,在Redux Reducer更新时更新本地状态

时间:2018-11-17 04:46:10

标签: reactjs redux react-redux

我正在使用React和Redux进行项目。我正在用一个数组更新一个reducer,然后将该数组映射到一个组件中。该组件具有用于有条件地渲染图像的状态。我希望每当reducers状态更新时,此组件状态都将重置为默认状态。

这是减速器:

const reducer = (state={board : []}, action) => {
    switch (action.type) {
      case 'MAKE_BOARD':
      return Object.assign({}, state, {
        board: action.payload
      })
      default:
        return state  
    }
}

这是App.js页面,它调用reducer:

import React, { Component } from 'react';
import './App.css';
import Board from '../Board/Board'
import {connect} from 'react-redux'


const mapReduxStateToProps= (reduxState) => ({
  reduxState
})

class App extends Component {
  state = {
    size : '8',
    squareArray : []
  }

  handleChange =(event) => {
    this.setState({
      ...this.state,
      size : Number(event.target.value)
    })
    console.log(this.state)
  }

  //This function makes a an array of numbers with 1/4 'X's and 3/4 'O's
  boardMaker = (number) => {
    this.setState({squareArray:[]});
    let size = number*number;
    let placeHolderArray = []

    for(let i=0; i<size; i++){
      placeHolderArray.push('O')
    }
    for(let j=0; j<size/4;j++){
      placeHolderArray[Math.floor(Math.random()*size)] = 'X'
    }

    this.setState({squareArray: placeHolderArray})
    console.log(placeHolderArray)
    console.log(this.state.squareArray);
    this.props.dispatch({type:'MAKE_BOARD', payload: placeHolderArray})
    this.props.dispatch({type: 'SET_SIZE', payload : this.state.size})
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <input onChange={this.handleChange} placeholder='Size'/>
          <button onClick={()=>this.boardMaker(this.state.size)}>Make Board</button>

          <div className='board' style={{width: 40*this.props.reduxState.size.size}}>

            {/* {this.state.squareArray.map(space => {
              return(
                <div className='square'>{space}</div>
              )
            })} */}
            {JSON.stringify(this.props.reduxState)}
            {this.props.reduxState.reducer.board.map((space,index) => 
              <Board keys={index} id={space}/>
            )
            }
          </div>

        </header>
      </div>
    );
  }
}

export default connect(mapReduxStateToProps)(App);

这是将reducer映射到的board.js:

import React, { Component } from 'react';
import './Board.css'
import { connect } from 'react-redux';


const mapReduxStateToProps = (reduxState) => ({reduxState})

class Board extends Component {
  state = {
    clicked: false,
    displayFlag: false,
    counter: 0,
  }


  imageDisplay= () => {
    if(!this.state.clicked && !this.state.displayFlag){
      return <img key={this.props.id} src='images/Frog-1.png' alt='Not Clicked'/>
    } else if(this.state.displayFlag){
      return <img src='images/Yellow.png' alt='None' />
    } else {
      return this.state.counter;
    }
  }

  handleMouseDown =  e => {
    document.oncontextmenu = function() {
      return false;
  }
    e = e || window.event;
    //console.log(e.which)
    console.log(this.state)
    switch(e.which) {
      case 1 : this.showNumber(); break;
      case 2 : break;
      case 3 : this.displayFlag(); return false;
      default: break;  
    }
  }

  displayFlag= () => {
    console.log('running')
    this.setState({...this.state, displayFlag : !this.state.displayFlag })
    return this.state.displayFlag;
  }

  showNumber= () => {
    console.log('run')
    let Xcounter = 0;
    let edge = Math.sqrt(this.props.reduxState.reducer.board.length)
    console.log(edge)
    let keys = this.props.keys
    let board = this.props.reduxState.reducer.board
    let minX = keys%edge === 0 ? 0 : -1;
    let maxX = keys%edge === (edge-1) ? 0 : 1;
    let minY = Math.floor(keys/edge) == 0 ? 0 : -1;
    let maxY = Math.floor(keys/edge) == (edge-1) ? 0 : 1;
    for(let x = minX; x <= maxX; x++){
      for(let y = minY; y<=maxY; y++){
        if(board[keys+x+(y*edge)]=== 'X'){
          Xcounter++

        }
      }
    }
    if(this.props.id === 'X'){
      this.setState({...this.state, clicked: true, counter: 'X'})
      return this.state.counter;
    }
    this.setState({...this.state, clicked: true, counter: Xcounter})
    return this.state.counter;
  }



  render() {
    return (
      <div className="App">
          <div onMouseDown={()=>this.handleMouseDown()} className='square'>{this.imageDisplay()}</div>

      </div>
    );
  }
}

export default connect(mapReduxStateToProps)(Board);

我希望在减速器更新时重置板上的本地状态。我可能可以通过向reducer添加属性并在组件中使用它们来做到这一点,但我希望有更好的方法。

2 个答案:

答案 0 :(得分:1)

查看用例-您需要在每个MAKE_BOARD 操作中清空本地状态。

这是我想到的两种方法-

  1. 您可以检查正在更新的道具,并在您的(取决于您的反应版本)生命周期方法中放置条件,例如componentWillReceiveProps / getDerivedStateFromProps / componentDidUpdate,然后清空您的道具本地状态。
  2. 您可以在RESET_ACTION_NAME的行上创建一个单独的操作,该操作将在每次更新时返回您的初始状态(为空)。但是要使其正常运行,您需要将本地状态作为对象放置在redux存储中。

PS:如果您知道重置状态的操作范围有限,则无需将状态放入存储中。但是,如果您知道此操作跨越多个组件,则可以考虑将本地状态转换为redux存储对象。

答案 1 :(得分:0)

这有点涉及设计意见领域,但是我认为处理此问题的最直接方法是将电路板的状态也置为redux而不是局部状态(可能在同一商店的独立减速器中),因为(如果我理解正确的话)您是在说要根据“ MAKE_BOARD”操作更改其状态。

另一种替代方法是在redux状态下包含一个整数板ID,每次重新制作该板时,该ID都会增加。然后,如果您将其用作开发板的“关键”属性,我相信这将导致它自动重置,因为它将卸载上一个开发板并创建一个新的开发板。

如果您想要更多有关此操作的实现细节,建议将代码版本放入Codepen或codesandbox中,并在您的问题中共享它(但是最好包含大多数相关代码)直接在您的问题文本中。)