Я использую реагировать с редуксом, и у меня есть список задач.У меня есть компонент 'Todos', который действует как контейнер, и компонент 'Todoitem', который содержит все задачи.Все работает нормально - редукторы изменяют состояние и обновляются с новыми данными, но дочерний компонент (он же компонент Todoitem) не будет перерисовываться.
Todos.js:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import TodoItem from "./TodoItem";
class Todos extends Component {
render() {
return (
<div className="Todos">
<div className="todos_title"> {this.props.title} </div>
{this.props.todos.map(todo => {
console.log(todo); // this line prints updated data from state just fine!
return <TodoItem todo={todo} key={todo.id}></TodoItem>;
})}
</div>
);
}
}
// PropTypes
Todos.propTypes = {
todos: PropTypes.array.isRequired
};
const mapStateToProps = state => ({
todos: state.todosReducer.todos
});
export default connect(mapStateToProps)(Todos);
TodoItem.js:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { checkTodo } from "../actions/todosAction";
class TodoItem extends Component {
onChange = (e, id) => {
console.log(this.props.todo.completed.toString()); // this also prints fine the updated data
this.props.checkTodo(id); // dispatches an action to the reducer to toggle the todo.completed with the right todo.id
};
render() {
console.log('rendering'); // this is the problem - this line calls only in the first rendering, but not when state changes
let { id, title, completed } = this.props.todo;
return (
<div className={completed ? "TodoItemDone" : "TodoItem"}>
<p>
<input
className="todo_cb"
type="checkbox"
onChange={e => this.onChange(e, id)}
checked={completed ? "checked" : ""}
/>
{id}) {title}
</p>
</div>
);
}
}
// PropTypes
TodoItem.propTypes = {
todo: PropTypes.object.isRequired
};
const mapDispatchToProps = dispatch => ({
checkTodo: todo => dispatch(checkTodo(todo))
});
const mapStateToProps = state => ({});
export default connect(
null,
mapDispatchToProps
)(TodoItem);
Я заметил, что если я передаю mapStateToProps в дочернем компе, то это повторный рендеринг, например:
const mapStateToProps = state => ({
some_prop: state
});
Я понимаю, еслиЯ использую mapStateToProps в потомке, который он перерисовывает, но мне ничего не нужно напрямую из состояния в потомке, родитель делает это.Это имеет некоторый смысл, но мои задачи хранятся в массиве в состоянии, и я сопоставляю их, как вы видите в родительском компоненте, поэтому я не могу отобразить конкретную задачу из этого массива в подпорки компонента (как я могу различитькаждый элемент в массиве сопоставить с подпоркой?).
Я очень запутался.Я читал, что компонент повторно рендерится, когда состояние или его реквизит меняются.Внутри дочернего компонента реквизиты действительно изменяются, потому что родительский объект рендерится повторно, и он повторяет задачи снова и возвращает компонент с новыми реквизитами.Может быть, это не способ передать задачи компонентам, но я до сих пор не понимаю, почему происходит изменение реквизита и не вызывается render ().
Большое спасибо!
Редактировать1:
Я подключил действие checkTodo к родительскому компоненту и передал функцию с помощью props, и она работает просто отлично.Тем не менее, я не понимаю, почему до того, как дочерний компонент не перерисовался с предыдущим кодом ...
Редактировать 2:
На самом деле я просто соврал, он не работает.Я забыл удалить mapStateToProps, который, как я сказал, сработал, поэтому я вернулся к исходной точке.
Редактировать 3:
Решено с помощью вызова forceUpdate ().До сих пор не могу понять, почему это произошло.