react-redux connect 不重新渲染组件,但 props 得到更新
react-redux connect do not re-render component, but props getting updated
我有一个关于 react-redux 的问题,我正在玩一些小的测试代码,以了解它是如何工作的。
Git repository with problematic code
一切看起来都是正确的,action generator、reducer、dispatcher、mapStateToProps 和 connect 函数。
我也会在这里粘贴代码:
无状态突变。
但是当子组件 Todo (index.jsx) 调用从主组件(有问题的组件)TodoBox (index.jsx) 传递给它的函数(onClick 事件)时,然后
1.调度员被解雇
2. reducer 被解雇并且 returns 具有预期更新的新状态
3. mapStateToProps 被解雇并且 returns 预期结果
但是TodoBox组件没有重新渲染
从浏览器控制台我可以看到 TodoBox 的 this.props 已更新值。
这是怎么回事,我看不懂,查了很多文章和例子都没有匹配。
谁能检测出问题,我需要帮助。
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 }
}
请检查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
}
我有一个关于 react-redux 的问题,我正在玩一些小的测试代码,以了解它是如何工作的。
Git repository with problematic code
一切看起来都是正确的,action generator、reducer、dispatcher、mapStateToProps 和 connect 函数。
我也会在这里粘贴代码:
无状态突变。
但是当子组件 Todo (index.jsx) 调用从主组件(有问题的组件)TodoBox (index.jsx) 传递给它的函数(onClick 事件)时,然后 1.调度员被解雇 2. reducer 被解雇并且 returns 具有预期更新的新状态 3. mapStateToProps 被解雇并且 returns 预期结果
但是TodoBox组件没有重新渲染 从浏览器控制台我可以看到 TodoBox 的 this.props 已更新值。
这是怎么回事,我看不懂,查了很多文章和例子都没有匹配。
谁能检测出问题,我需要帮助。
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 }
}
请检查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
}