Prawdopodobnie brakuje mi czegoś bardzo oczywistego i chciałbym to wyjaśnić.
Oto moje zrozumienie.
W naiwnym elemencie reagującym mamy states
& props
. Aktualizacja state
z setState
ponownym renderowaniem całego komponentu. props
są w większości tylko do odczytu i ich aktualizowanie nie ma sensu.
W komponencie reagującym, który subskrybuje sklep Redux, za pośrednictwem czegoś podobnego store.subscribe(render)
, jest on oczywiście ponownie renderowany za każdym razem, gdy sklep jest aktualizowany.
React-redux ma pomocnika, connect()
który wstrzykuje część drzewa stanu (który jest interesujący dla komponentu) i actionCreators jako props
komponent, zwykle poprzez coś w rodzaju
const TodoListComponent = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
Ale rozumiejąc, że a setState
jest niezbędna TodoListComponent
do reagowania na zmianę drzewa stanu Redux (ponowne renderowanie), nie mogę znaleźć żadnego state
lub setState
powiązanego kodu w TodoList
pliku komponentu. Brzmi mniej więcej tak:
const TodoList = ({ todos, onTodoClick }) => (
<ul>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
)
Czy ktoś może wskazać mi właściwy kierunek, czego mi brakuje?
PS Podążam za przykładem listy rzeczy do zrobienia dołączonej do pakietu Redux .
źródło
prev.a === current.a && prev.b === current.b && .....
. Zakłada się, że wszelkie zmiany danych spowodują nowe odwołania, co oznacza, że zamiast bezpośredniej mutacji wymagane są niezmienne aktualizacje danych.Moja odpowiedź jest trochę poza lewym polem. Rzuca światło na problem, który doprowadził mnie do tego postu. W moim przypadku wyglądało na to, że aplikacja nie renderowała się ponownie, mimo że otrzymała nowe rekwizyty.
Twórcy Reacta mieli odpowiedź na to często zadawane pytanie, coś w rodzaju tego, że jeśli (sklep) został zmutowany, w 99% przypadków reakcja nie będzie ponownie renderowana. Jeszcze nic o pozostałych 1%. W tym przypadku mutacja nie miała miejsca.
TLDR;
Krawędź obudowy: Po
state
aktualizacji, następnie aplikacja ma ponownie uczynić!Okazuje się, że jeśli twoja aplikacja używa tylko
state
do wyświetlania swoich elementów,props
może aktualizować, alestate
nie będzie, więc nie ma ponownego renderowania.Miałem
state
to zależne odprops
otrzymanego od Reduxstore
. Danych, których potrzebowałem, nie było jeszcze w sklepie, więc pobrałem jecomponentDidMount
, jak trzeba . Otrzymałem rekwizyty z powrotem, kiedy mój reduktor zaktualizował sklep, ponieważ mój komponent jest połączony przez mapStateToProps. Ale strona nie została wyrenderowana, a stan wciąż był pełen pustych ciągów.Przykładem tego jest sytuacja, w której użytkownik załadował stronę „edytuj post” z zapisanego adresu URL. Masz dostęp do
postId
adresu z adresu URL, ale informacjistore
jeszcze nie ma, więc możesz je pobrać. Elementy na Twojej stronie są kontrolowanymi komponentami - więc wszystkie wyświetlane dane znajdują się wstate
.Korzystając z Redux, dane zostały pobrane, sklep został zaktualizowany, a komponent jest
connect
edytowany, ale aplikacja nie odzwierciedlała zmian. Przy bliższym przyjrzeniu sięprops
otrzymaliśmy, ale aplikacja nie została zaktualizowana.state
nie zaktualizowany.Cóż,
props
będzie aktualizować i propagować, alestate
nie będzie. Musisz konkretnie powiedzieć,state
aby zaktualizować.Nie możesz tego zrobić w
render()
, acomponentDidMount
już skończyłeś swoje cykle.componentWillReceiveProps
to miejsce, w którym aktualizujeszstate
właściwości, które zależą od zmienionejprop
wartości.Przykładowe zastosowanie:
componentWillReceiveProps(nextProps){ if (this.props.post.category !== nextProps.post.category){ this.setState({ title: nextProps.post.title, body: nextProps.post.body, category: nextProps.post.category, }) } }
Muszę wypowiedzieć się na temat tego artykułu, który wyjaśnił mi rozwiązanie, o którym nie wspomniały dziesiątki innych postów, blogów i repozytoriów. Każdy, kto miał problem ze znalezieniem odpowiedzi na ten ewidentnie niejasny problem, oto jest:
Metody cyklu życia komponentów ReactJs - szczegółowe omówienie
źródło
React 16.3
pory powinieneś używaćgetDerivedStateFromProps
zamiastcomponentWillReceiveProps
. Ale w rzeczywistości nie powinieneś nawet robić tego wszystkiego, co wyartykułowano tutajTa odpowiedź jest podsumowaniem artykułu Briana Vaughna zatytułowanego You Probably Don't Need Derived State (07 czerwca 2018).
Wyprowadzanie stanu z rekwizytów jest anty-wzorcem we wszystkich jego formach. W tym starsze
componentWillReceiveProps
i nowszegetDerivedStateFromProps
.Zamiast wyprowadzać stan z rekwizytów, rozważ następujące rozwiązania.
Dwa zalecenia dotyczące najlepszych praktyk
Zalecenie 1. W pełni kontrolowany element
Zalecenie 2. W pełni niekontrolowany komponent z kluczemfunction 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} />
Dwie alternatywy, jeśli z jakiegokolwiek powodu zalecenia nie sprawdzają się w Twojej sytuacji.
Alternatywa 1: zresetuj niekontrolowany komponent za pomocą właściwości ID
Alternatywa 2: Zresetuj niekontrolowany komponent za pomocą metody instancjiclass 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 }); } // ... }
źródło
jak wiem jedyne co robi Redux, przy zmianie stanu sklepu wywołuje componentWillRecieveProps, jeśli twój komponent był zależny od zmutowanego stanu i wtedy powinieneś zmusić komponent do aktualizacji, tak jest
1-magazynowa zmiana stanu 2-wywołanie (componentWillRecieveProps (() => {3-składnikowa zmiana stanu}))
źródło