Я, вероятно, упускаю что-то очень очевидное и хотел бы очистить себя.
Вот мое понимание.
В наивном компоненте реакции у нас есть states
& props
. Обновление state
с setState
повторным оказывает весь компонент. props
в основном предназначены только для чтения, и их обновление не имеет смысла.
В компоненте реакции, который подписывается на хранилище redux через что-то вроде store.subscribe(render)
, он, очевидно, повторно отображает каждый раз, когда хранилище обновляется.
В response-redux есть помощник, connect()
который вводит часть дерева состояний (которая представляет интерес для компонента) и actionCreators в props
отношении компонента, обычно через что-то вроде
const TodoListComponent = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
Но с пониманием того, что a setState
необходим для TodoListComponent
реакции на изменение дерева состояний redux (повторный рендеринг), я не могу найти какой-либо state
или setState
связанный код в TodoList
файле компонента. Читается это примерно так:
const TodoList = ({ todos, onTodoClick }) => (
<ul>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
)
Может ли кто-нибудь указать мне в правильном направлении, что мне не хватает?
PS Я следую примеру списка задач, поставляемого с пакетом redux .
источник
prev.a === current.a && prev.b === current.b && .....
. Это предполагает, что любые изменения данных приведут к появлению новых ссылок, что означает, что требуются неизменяемые обновления данных вместо прямой мутации.Мой ответ немного необычный. Это проливает свет на проблему, которая привела меня к этой публикации. В моем случае казалось, что приложение не подвергалось повторному рендерингу, несмотря на то, что оно получило новые реквизиты.
У разработчиков React был ответ на этот часто задаваемый вопрос: если (хранилище) было изменено, в 99% случаев это причина, по которой реакция не будет повторно отображаться. Но про остальные 1% ничего. Мутации здесь не было.
TL; DR;
Пограничный случай: После
state
обновления, то приложение делает повторно вынести!Оказывается, если ваше приложение используется только
state
для отображения своих элементов, оноprops
может обновляться, ноstate
не обновляется , поэтому повторного рендеринга не требуется.У меня было
state
что зависело отprops
полученного от reduxstore
. Нужных мне данных еще не было в магазине, поэтому я взял ихcomponentDidMount
, как положено. Я вернул реквизиты, когда мой редуктор обновил хранилище, потому что мой компонент подключен через mapStateToProps. Но страница не отображалась, а состояние все еще было заполнено пустыми строками.Например, пользователь загрузил страницу редактирования сообщения с сохраненного URL. У вас есть доступ к
postId
URL-адресу, но информацииstore
еще нет, поэтому вы ее получите. Элементы на вашей странице - это контролируемые компоненты, поэтому все данные, которые вы показываете, находятся внутриstate
.Используя redux, данные были извлечены, хранилище обновлено и компонент был
connect
изменен, но приложение не отразило изменения. При ближайшем рассмотренииprops
были получены, но приложение не обновлялось.state
не обновлялся.Хорошо,
props
будет обновлять и распространять, ноstate
не будет. Вам нужно специально сообщитьstate
об обновлении.Вы не можете сделать это в
render()
, иcomponentDidMount
уже закончили его циклы.componentWillReceiveProps
здесь вы обновляетеstate
свойства, которые зависят от измененногоprop
значения.Пример использования:
componentWillReceiveProps(nextProps){ if (this.props.post.category !== nextProps.post.category){ this.setState({ title: nextProps.post.title, body: nextProps.post.body, category: nextProps.post.category, }) } }
Я должен отдать должное этой статье, которая просветила меня о решении, которое не упоминалось в десятках других сообщений, блогов и репозиториев. Любой другой, у кого возникли проблемы с поиском ответа на эту явно неясную проблему, вот он:
Методы жизненного цикла компонентов ReactJs - глубокое погружение
источник
React 16.3
момента вы должны использоватьgetDerivedStateFromProps
вместоcomponentWillReceiveProps
. Но на самом деле вы даже не должны делать все это так, как здесьЭтот ответ представляет собой краткое изложение статьи Брайана Вона, озаглавленной « Вам, вероятно, не нужно производное состояние» (7 июня 2018 г.).
Получение состояния из props - это антипаттерн во всех его формах. В том числе с использованием старых
componentWillReceiveProps
и новыхgetDerivedStateFromProps
.Вместо того, чтобы получать состояние из свойств, рассмотрите следующие решения.
Две лучшие практические рекомендации
Рекомендация 1. Полностью управляемый компонент
Рекомендация 2. Полностью неконтролируемый компонент с ключом.function EmailInput(props) { return <input onChange={props.onChange} value={props.email} />; }
// parent class class EmailInput extends Component { state = { email: this.props.defaultEmail }; handleChange = event => { this.setState({ email: event.target.value }); }; render() { return <input onChange={this.handleChange} value={this.state.email} />; } } // child instance <EmailInput defaultEmail={this.props.user.email} key={this.props.user.id} />
Две альтернативы, если по какой-либо причине рекомендации не работают в вашей ситуации.
Альтернатива 1: сбросить неконтролируемый компонент с помощью ID prop
Альтернатива 2: сбросить неуправляемый компонент с помощью метода экземпляраclass EmailInput extends Component { state = { email: this.props.defaultEmail, prevPropsUserID: this.props.userID }; static getDerivedStateFromProps(props, state) { // Any time the current user changes, // Reset any parts of state that are tied to that user. // In this simple example, that's just the email. if (props.userID !== state.prevPropsUserID) { return { prevPropsUserID: props.userID, email: props.defaultEmail }; } return null; } // ... }
class EmailInput extends Component { state = { email: this.props.defaultEmail }; resetEmailForNewUser(newEmail) { this.setState({ email: newEmail }); } // ... }
источник
поскольку я знаю, что только redux делает, при изменении состояния хранилища вызывает componentWillRecieveProps, если ваш компонент зависел от мутированного состояния, а затем вы должны заставить свой компонент обновлять его, как это
1-store State change-2-call (componentWillRecieveProps (() => {3-компонентное изменение состояния}))
источник