Узнав о React Router, я заметил, что компонент возвращается в исходное состояние при переключении с маршрута от а до б.
Почему этого не происходит при повторном нажатии на тот же маршрут, т.е. а к а?
Как я могу реализовать способ, при котором при нажатии на тот же маршрут <NavLink/> компонент возвращается в исходное состояние - следует ли/можно ли это сделать на крючке onChange React Router?
Если это антишаблон, пожалуйста, просветите меня, как еще я мог бы выполнить следующее: мне нужно, чтобы мой компонент возвращался в исходное состояние не только при переключении маршрутов, но и в случае, когда пользователь выбирает снова щелкает тот же маршрут.
Ниже абстракция проблемы:
Щелчок по тегу Cat <p/> должен изменить его цвет на green, щелчок по тому же маршруту <NavLink to = "/cat-view">cat</NavLink> должен вернуть состояние цвета кошки обратно в исходное состояние. то есть color: false
Так же, как и при переключении с маршрута от а до б (в моем случае кошка на собаку)
// Cat Component
import React, { useState } from "react";
export const Cat = () => {
const [color, setColor] = useState(false);
function ChangeColor() {
setColor(true);
}
console.info(color)
return (
<p onClick = {ChangeColor}>
Click on this <span className = {color ? "green" : " "}>Cat</span>
</p>
);
};
import {
BrowserRouter as Router,
Route,
NavLink,
Switch,
withRouter,
browserHistory
} from "react-router-dom";
// Main Component
class PetShop extends Component {
state = {};
render() {
return (
<Router history = {browserHistory}>
<div>
<ul>
<li>
<NavLink to = "/">home</NavLink>
</li>
<li>
<NavLink to = "/cat-view">cat</NavLink>
</li>
<li>
<NavLink to = "/dog-view">dog</NavLink>
</li>
</ul>
<Switch>
<Route
path = "/cat-view"
render = {() => <Cat/>}
onChange = {console.info("cat route changed")}
/>
<Route
path = "/dog-view"
render = {() => <Dog/>}
onChange = {console.info("dog route changed")}
/>
</Switch>
</div>
</Router>
);
}
}
export default withRouter(PetShop);
вот песочница кода



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Поскольку вы используете компонент react-router Switch, который отображает только первое совпадение, при переключении с Route а на ба размонтируется; это отбрасывает все его состояние, поэтому, если вы переключитесь обратно на а, у вас будет совершенно новый компонент, который получает начальное значение, указанное вами для его состояния (например, false для Catcolor). Щелчок по NavLink, который не меняет отображаемый Route, оставляет тот же элемент на месте и не влияет на его состояние.
Если вы хотите изменить состояние при нажатии на его NavLink, то вам нужно сделать это явно.
Есть два основных способа сделать это:
Вот модифицированная версия вашей песочницы, которая демонстрирует все это:
Cat демонстрирует первый подход.
Я переместил состояние с Cat на PetShop (Cat теперь использует только props). Я также добавил onClick в NavLink для кота, который возвращает состояние false.
Dog демонстрирует второй подход.
Этот подход будет лучше работать в более сложном сценарии, когда компонент имеет много собственных состояний, и вы хотите, чтобы все они были сброшены, если вы снова нажмете на ссылку.
Bunny демонстрирует третий подход.
Это похоже на ключевое свойство для примера с собакой, но не вызывает повторного монтирования. Bunny просто использует resetIndex, чтобы заставить Bunny сбросить себя. Вероятно, для этого существует несколько технических подходов. Вам просто нужен способ сигнализировать ребенку, чтобы он перезагрузил себя.
@ Jonca33 Jonca33 Во многом это зависит от вашего реального сценария. Если вам нужен полный сброс вашего компонента, то перемонтирование может быть уместным, но этот будет фактически удаляет элемент (и его потомков) из DOM и добавляет новый элемент на его место. В некоторых сценариях это нормально и намного проще, чем альтернативы, и в других случаях, когда это было бы неуместно.
@ Jonca33 Jonca33 Вы также должны быть осторожны с этим подходом, чтобы случайно не вызвать его рендеринг дважды каждый раз, когда вы нажимаете ссылку - один раз со старым ключом и один раз с новым ключом.
В этом есть смысл. Моя настоящая проблема (которую я решил не показывать здесь, потому что это было бы слишком многословным кодом) — это компонент child, который получает несколько изменений пользовательского интерфейса на основе взаимодействия с пользователем. Основываясь на вашем объяснении, правильно ли я предполагаю, что было бы лучше сделать то, что вы сделали с dog, и поднять состояние, чтобы исправить ситуацию?
@ Jonca33 Jonca33 Я добавил третий подход (Bunny), который позволяет избежать повторного монтирования, но позволяет дочернему элементу по-прежнему контролировать сброс (вместо того, чтобы поднимать все состояние до родительского).
props.resetRef.current... каждый день узнаешь что-то новое! Где я могу прочитать больше о таком подходе? Спасибо!
@ Jonca33 Jonca33 Я добавил альтернативный подход для примера Bunny.
@RyanCogswell, спасибо, я тоже искал такое решение. мир!
@RyanCogswell Я следил за этой веткой здесь ... К вашему сведению, Bunny перестал работать, когда вы заменили resetRef на useEffect.
@NullisTrue Спасибо - у меня возникла проблема с синтаксисом при вызове useEffect. Я не заключал props.resetIndex в массив.
@ Jonca33 Jonca33 Я думаю, что подход ref проблематичен, поэтому я удалил его. В определенных сценариях это могло привести к обновлению состояния несмонтированного компонента.
Большое спасибо, Райан! Насколько вам известно, я прошу антипаттерн для «Святого Грааля» React, а также не ухудшит ли реализация
key, как вы описали в компонентеDog, производительность и оптимизацию React?