React-Redux道具不更新

时间:2019-11-06 23:11:08

标签: reactjs redux

我正在尝试将d3与react结合使用以生成图以最终实现排序算法可视化工具。我在render函数中有代码return <svg ref={node=>this.node=node}/>,并且在名为renderSvg()的函数中调用了节点,该函数在componentDidUpdate中进行了调用。看来道具没有更新。

我已经进行了一些研究,并且了解最常见的原因是状态更新时的状态。但是,我已经检查了我的代码,无论如何我似乎都没有修改原始状态。在任何状态部分中都没有任何对象,但是在有数组的地方,我使用了散布运算符来确保不修改原始对象。我想知道是否与我正在使用Redux.combineReducers有关。我不是要测试实际的排序算法,是的,我仍在尝试获取随机生成的数组以在svg中可视化呈现。请注意,如果有任何区别,我也会使用reduxThunk

有人可以帮忙吗?如果它是combineReducers函数,是否可以解决? Here is a link to my project,下面是我的代码:

$(function(){
  //REDUC
  //array action types
  const GENERATE_ARRAY = 'GENERATE_ARRAY';
  const SORT_ARRAY = 'SORT_ARRAY';

  //accessCount action types
  const INCREMENT_ACCESS_COUNTER = 'INCREMENT_ACCESS_COUNTER';
  const RESET_ACCESS_COUNTER = 'RESET_ACCESS_COUNTER';

  //indexing action types
  const ACCESSING_INDICES = 'ACCESSING_INDICES'
  const MIN_INDEX = 'MIN_INDEX';
  const MAX_INDEX = 'MAX_INDEX';
  const SORTED_INDICES = 'SORTED_INDICES';

  //array action generators
  function generateArray(value){
    return {type: GENERATE_ARRAY, value};
  }
  function sortArray(algorithm){
    return {type: SORT_ARRAY, algorithm};
  }

  //accessCounter action generators
  function incrementAccessCounter(){
    return {type: INCREMENT_ACCESS_COUNTER};
  }
  function resetAccessCounter(){
    return {type: RESET_ACCESS_COUNTER};
  }

  //sortedIndices and accessingIndices action generators
  function updateSortedIndices(value){
    return {type: SORTED_INDICES, value};
  }
  function updateAccessingIndices(value){
    return {type: ACCESSING_INDICES, value};
  }

  //max and min index action generators
  function setMinIndex(index){
    return {type: MIN_INDEX, index};
  }
  function setMaxIndex(index){
    return {type: MAX_INDEX, index};
  }

  //initial values
  const INITIAL_ARRAY = [];
  const INITIAL_INDEX = -1;
  const INITIAL_ACCESS_COUNTER = 0;
  const INITIAL_STATE = {
    array: [],
    accessCounter: INITIAL_ACCESS_COUNTER,
    sortedIndices: [],
    accessingIndices: [],
    minIndex: INITIAL_INDEX,
    maxIndex: INITIAL_INDEX 
  }

  //state reducers
  function arrayReducer(state = [], action){
    switch(action.type){
      case GENERATE_ARRAY:
        if (Array.isArray(action.value))
          return action.value;
        let result = [];
        for (let i = 0; i < action.value; i++)
          result.push(Math.random());
        return result;
      default: return [...state];
    }
  }

  function sortedIndicesReducer(state = [], action){
    switch(action.type){
      case SORTED_INDICES:
        if (Array.isArray(action.value))
          return [...action.value];
        return [...state, action.value];
      default: return [...state];
    }
  }

  function accessingIndicesReducer(state = [], action){
    switch(action.type){
      case ACCESSING_INDICES:
        if (Array.isArray(action.value))
          return [...action.value];
        return [...state, action.value];
      default: return [...state];
    }
  }

  function accessCounterReducer(state = INITIAL_ACCESS_COUNTER, action){
    switch(action.type){
      case INCREMENT_ACCESS_COUNTER: return state + 1;
      case RESET_ACCESS_COUNTER: return 0;
      default: return state;
    }
  }

  function minIndexReducer(state = INITIAL_INDEX, action){
    switch(action.type){
      case MIN_INDEX: return action.index;
      default: return state;
    }
  }

  function maxIndexReducer(state = INITIAL_INDEX, action){
    switch(action.type){
      case MAX_INDEX: return action.index;
      default: return state;
    }
  }

  const rootReducer = Redux.combineReducers({
    array: arrayReducer,
    accessCounter: accessCounterReducer,
    sortedIndices: sortedIndicesReducer,
    accessingIndices: accessingIndicesReducer,
    minIndex: minIndexReducer,
    maxIndex: maxIndexReducer
  });

  const store = Redux.createStore(rootReducer, Object.assign({},INITIAL_STATE), Redux.applyMiddleware(ReduxThunk.default));

  //sorting algorithms
  const sortingAlgorithms = [
    {
      name: 'Selection Sort',
      algorithm: function(){
        return function(dispatch, getState){
          dispatch(resetAccessCounter());
          dispatch(updateSortedIndices([]));
          let array = [...getState().array];
          let sorted = [...getState().sortedIndices];
          for (let i = 0; i < array.length; i++){
            let minIndex = i;
            for (let j = 0; j < array.length; j++){
              let accessing = j;
              minIndex = array[j] < array[minIndex]
              ? j : minIndex;
              dispatch(incrementAccessCounter());
              dispatch(updateAccessingIndices([accessing]));
              if (minIndex != j)
                dispatch(setMinIndex(minIndex));
            }
            dispatch(updateAccessingIndices([]));
            let tmp = array[i];
            array.splice(i, 1, array[minIndex]);
            array.splice(minIndex, 1, tmp);
            dispatch(setMinIndex(-1));
            dispatch(generateArray(array));
            dispatch(updateSortedIndices(i));
          }
        }
      }
    },
    {
      name: 'Bubble Sort',
      algorithm: function(){
        return function(dispatch, getState){

        };
      }
    }
  ];



  //React
  class Form extends React.Component{
    constructor(props){
      super(props);
      this.state = {
        length: '1000',
        algorithm: sortingAlgorithms[0].algorithm
      }
      this.algorithmHandler = this.algorithmHandler.bind(this);
      this.lengthHandler = this.lengthHandler.bind(this);
      this.generateHandler = this.generateHandler.bind(this);
      this.sortHandler = this.sortHandler.bind(this);
    }
    algorithmHandler(event){
      this.setState({algorithm: event.target.value});
    }
    lengthHandler(event){
      this.setState({length: event.targer.value});
    }
    generateHandler(event){
      event.preventDefault();
      console.log('before:', this.props, store.getState());
      this.props.generateArray(parseInt(this.state.length));
      console.log('after:', this.props, store.getState());
    }
    sortHandler(event){
      event.preventDefault();
      this.props.sort(this.state.algorithm);
    }
    render(){
      return(
        <div>
          <h1 class='text-center'>SortingAlgorithms</h1>
          <form>
            <label for='algorithm'>
              Algorithm: 
              <select
                id='algorithm'
                class='form-control'
                value={this.state.algorithm}
                onChange={this.algorithmHander}>
                {sortingAlgorithms.map(function(e){
                  return (
                    <option value={e.algorithm}>
                      {e.name}
                    </option>
                  );
                })}
              </select>
            </label>
            <label for='array-length'>
              <input
                id='array-length'
                class='form-control'
                type='number'
                min='10'
                max='10000'
                value={this.state.length}
                onChange={this.lenghtHandler}/>
            </label>
            <button
              id='generate'
              class='btn btn-primary'
              onClick={this.generateHandler}>
              Generate Random Array
            </button>
            <button
              id='sort'
              class='btn btn-primary'
              onClick={this.sortHandler}>
              Sort Array
            </button>
          </form>
        </div>
      )
    }
  }

  class Svg extends React.Component{
    constructor(props){
      super(props);
      this.renderSvg = this.renderSvg.bind(this);
    }
    componenDidUpdate(){
      this.renderSvg();
    }
    componentDidMount(){
      this.renderSvg();
    }
    renderSvg(){
      const svgPadding = 50;
      const svgWidth = 900;
      const svgHeight = 540;

      var svg = d3.select(this.node)
      .attr('width', svgWidth)
      .attr('height', svgHeight);

      //scales
      const xScale = d3.scaleBand()
      .domain([0, this.props.data.length])
      .range([svgPadding, svgWidth-svgPadding]);
      const yScale = d3.scaleLinear()
      .domain(d3.extent(this.props.data))
      .range([svg-svgHeight, svgPadding]);

      svg.selectAll('.bar')
      .data(this.props.data)
      .enter().append('rect')
      .attr('class', 'bar')
      .attr('x', (d, i)=>xScale(i))
      .attr('y', d=>yScale(d))
      .attr('fill', 'black');
    }
    render(){
      return <svg ref={node=>this.node=node}/>
    }
  }

  //ReactRedux
  const Provider = ReactRedux.Provider;
  const connect = ReactRedux.connect;

  function mapStateToProps(state){
    return {
      data: state.array,
      accessCounter: state.accessCounter,
      sortedIndices: state.sortedIndices,
      accessingIndices: state.accessingIndices,
      minIndex: state.minIndex,
      maxIndex: state.maxIndex
    };
  }

  function mapDispatchToProps(dispatch){
    return {
      generateArray: length => dispatch(generateArray(length)),
      sort: algorithm => dispatch(algorithm())
    };
  }

  const FormConnection = connect(mapStateToProps, mapDispatchToProps)(Form);
  const SvgConnection = connect(mapStateToProps, null)(Svg);

  class Wrapper extends React.Component{
    render(){
      return(
        <Provider store={store}>
          <FormConnection/>
          <SvgConnection/>
        </Provider>
      );
    }
  }

  ReactDOM.render(<Wrapper/>, $('body')[0]);
})

0 个答案:

没有答案