2017-03-02 165 views
3

我有一个关于react-redux的问题,我正在玩一些小的测试代码,以了解它是如何工作的。react-redux connect不重新渲染组件,但道具得到更新

Git repository with problematic code

一切看起来正确,动作生成器,减速机,调度员,mapStateToProps和连接功能。

我也会在这里粘贴代码:

没有状态变异。

但是,当子藤传递给它从主(问题的组件)TodoBox(index.jsx)(index.jsx)调用函数(onClick事件),然后 1.调度员被炒鱿鱼 2.减速,都会激发和回报与预期的更新 3. mapStateToProps新的国家,都会激发和收益预期的结果

但TodoBox组件,请不要重新渲染 从浏览器控制台,我可以看到this.props的TodoBox已更新的值。

这是怎么回事,我不明白,检查了很多文章和例子,但没有匹配。

谁能检测到问题,我需要帮助。

app.js(反应入口点)

import React from 'react'; 
 
import ReactDOM from 'react-dom'; 
 
import TodoBox from './views/index.jsx'; 
 
import { createStore } from 'redux'; 
 
import { Provider } from 'react-redux'; 
 
import * as actions from './redux_actions.js'; 
 

 
var data = JSON.parse(document.getElementById('initial-data').getAttribute('data-json')); 
 

 
const todosReducer = function (state={todos: data}, action) { 
 
    switch(action.type) { 
 
    case actions.UPDATE_TODO: 
 
     let newState = Object.assign({}, state) 
 
     let upd1 = updateRow(newState.todos, 'titel', action.todoUpdate.id, 'checked', action.todoUpdate.checked) 
 
     newState.todos = updateRow(upd1, 'titel', action.todoUpdate.id, 'detail', action.todoUpdate.checked ? 'Done' : 'Sorry not done') 
 
     return newState 
 
     break; 
 
    default: 
 
     return state; 
 
    } 
 
} 
 

 
function updateRow(tab, where, val, updfield, val2) { 
 
    tab.forEach((row) => { 
 
     row[where] === val ? row[updfield] = val2 : null 
 
    }) 
 
    return tab 
 
} 
 

 
var Store = createStore(todosReducer) 
 

 
ReactDOM.render(<Provider store={Store}><TodoBox /></Provider>, document.getElementById("app"));

index.jsx

import React from 'react'; 
 
import * as Redux from 'redux'; 
 
import { connect } from 'react-redux' 
 
import * as actions from '../redux_actions.js' 
 

 

 
class TodoBox extends React.Component { 
 
     render() { 
 
      return (
 
       <div className="todoBox"> 
 
        <h1>Todos</h1> 
 
        <TodoList data={this.props.todos} func={this.props.handleChange}/> 
 
        <TodoForm /> 
 
       </div> 
 
      ); 
 
     } 
 
    } 
 

 

 

 
class TodoList extends React.Component { 
 
    render() { 
 
    let todo = this.props.data.map((todos) => { return <Todo titel={todos.titel} func={this.props.func} check={todos.checked} key={todos.titel}>{todos.detail}</Todo> }) 
 
    return (
 
     <div className="todoList"> 
 
      <table style={{border: "2px solid black"}}> 
 
       <tbody> 
 
       {todo} 
 
       </tbody> 
 
      </table> 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 

 
class Todo extends React.Component { 
 
    render() { 
 
    return (
 
     <tr> 
 
     <td style={style.tableContent}> 
 
      <input id={this.props.titel} type="checkbox" checked={this.props.checked} onChange={this.props.func}/> 
 
     </td> 
 
     <td style={style.tableContent}>{this.props.titel}</td> 
 
     <td style={style.tableContent}>{this.props.children}</td> 
 
     </tr> 
 
    ); 
 
    } 
 
} 
 

 

 
Todo.propTypes = { 
 
    titel: React.PropTypes.string.isRequired 
 
} 
 

 

 
class TodoForm extends React.Component { 
 
    render() { 
 
    return (
 
     <div className="todoForm"> 
 
     I am a TodoForm. 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
let style = { 
 
     tableContent: { 
 
      border: "1px solid black" 
 
     } 
 
    }; 
 

 

 
const mapStateToProps = function (state) { 
 
    return { todos: state.todos } 
 
} 
 

 
const mapDispatchToProps = function(dispatch) { 
 
    return { 
 
    handleChange: function(event) { 
 
     dispatch(actions.actionUpdateTodo({id: event.target.id, checked: event.target.checked})); 
 
    } 
 
    } 
 
} 
 

 
export default connect(mapStateToProps, mapDispatchToProps)(TodoBox)

redux_actions.jsx

export const UPDATE_TODO = 'UPDATE_TODO' 
 

 
export function actionUpdateTodo(todoUpdate) { 
 
    return { type: UPDATE_TODO, todoUpdate: todoUpdate } 
 
}

回答

0

请检查http://redux.js.org/docs/Troubleshooting.html

看来你是变异的商店。问题在于你的减速器。

我强烈建议您阅读pure functions

const todosReducer = function (state={todos: data}, action) { 
    switch(action.type) { 
    case actions.UPDATE_TODO: 
     let newState = Object.assign({}, state) 
     let upd1 = updateRow(newState.todos, 'titel', action.todoUpdate.id, 'checked', action.todoUpdate.checked) 
     newState.todos = {...updateRow(upd1, 'titel', action.todoUpdate.id, 'detail', action.todoUpdate.checked ? 'Done' : 'Sorry not done')} //should do the trick. Although I would strongly suggest you to refactor the updateRow function. 
     return newState //even so you are returning a newState, the reference value (todos) is not a new instance. 
     break; 
    default: 
     return state; 
    } 
} 

function updateRow(tab, where, val, updfield, val2) { 
    tab.forEach((row) => { 
     row[where] === val ? row[updfield] = val2 : null 
    }) 
    return tab 
} 
+0

谢谢你的回答!我认为'让newState = Object.assign({},state)'创建全部新对象和所有内容。其实我不明白它为什么会发生变异。使用扩展运算符它没有工作,但下一个建设工作'newState.todos = Object.assign([],updateRow(upd1,'titel',action.todoUpdate.id,'detail',action.todoUpdate.checked?'Done ':'对不起'))' – sigvamo