Я не знаю, как использовать только один источник данных в зависимости от того, исходят ли эти данные от URL-адреса или кнопки.
Это действительно вся идея использования Redux, или какая-то другая система управления состоянием - наличие одного универсального хранилища истины для всего приложения, чтобы вы всегда знали, откуда поступают ваши данные. Так что да, в конечном итоге было бы лучше реализовать что-то подобное, и вы, вероятно, захотите это после того, как столкнетесь с огромными состояниями React и буровыми работами, но это ни в коем случае не является существенным. ваши данные containers
находятся достаточно высоко в дереве компонентов для всех компонентов, которым они нужны для доступа к ним, вы можете передать их им через props. Контейнеры всегда будут жить только в одном месте, поэтому вы можете быть уверены, что если его там нет, его нужно доставить. Из всего вашего прокомментированного кода немного неясно, действительно ли ContainerMain
должен отображать ContainerContents
, но, допустим, это не так. Вот упрощенная версия вашей структуры компонентов - идея в основном заключается в том, что вы проверяете, существует ли свойство данных, прежде чем запрашивать его в дочернем элементе.
Настройка родительского компонента, который отвечает за хранение всех containers
:
export default function App() {
const [containers, setContainers] = useState([]);
return (
<Router>
<Switch>
<Route exact path="/">
<ContainerMain
containers={containers}
setContainers={setContainers}
/>
</Route>
<Route exact path="/containercontents/:id">
<ContainerContents
containers={containers}
setContainers={setContainers}
/>
</Route>
</Switch>
</Router>
);
}
Компонент, из которого мы извлекаем все containers
, отправляя их родительскому объекту и получая их обратно как реквизиты:
function ContainerMain({ containers, setContainers }) {
const history = useHistory();
const getContainers = async () => {
const url = "/api/containers";
await fetch(url)
.then(response => response.json())
.then(response => setContainers(response))
.catch(() =>
console.log("Can’t access " + url + " response. Blocked by browser?")
);
};
useEffect(() => {
getContainers();
}, [getContainers]);
return (
<div>
<strong>MY FOOD CONTAINERS</strong>
<br />
<br />
<ul>
{containers.map(container => (
<li key={container.id}>
<div>
<button
onClick={() =>
history.push(`/containercontents/${container.id}`)
}
className="button is-primary"
>
{container.name}
</button>
</div>
</li>
))}
</ul>
</div>
);
}
Specifi c container
component. Если контейнер не существует в родительском состоянии, выберите его - функция возврата автоматически отобразит его, если / когда он существует в родительском состоянии.
function ContainerContents({ containers, setContainers }) {
const match = useRouteMatch();
useEffect(() => {
const fetchContainer = async id => {
let url = `/api/containers/${id}`;
await fetch(url)
.then(response => response.json())
.then(response => {
setContainers([...containers, response]);
})
.catch(() =>
console.log("Can’t access " + url + " response. Blocked by browser?")
);
};
const found = containers.find(el => el.id === match.params.id);
if (!found) {
fetchContainer(match.params.id);
}
}, [match.params, containers, setContainers]);
function selectContainer() {
const found = containers.find(el => el.id === match.params.id);
return found ? (
<div>
<h1>{found.name}</h1>
</div>
) : null;
}
return selectContainer();
}