Star Wars API

1

Hej,

próbuję zrobić aplikację która pobiera API Star Wars.
Mam jednak kilka problemów. Pierwszy fetch pobiera mi wszystkie dane, ale niektóre z nich są kolejnymi linkami które należy pobrać.
Najpierw starałem się to zrobić w komponencie CharactersTable mapując dataCharacters i robiąc np.

homeworldCol: fetch(character.homeworld).then(response => response.json().then((data) => data.name)

ale pojawia się error ** Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead. ** i zupełnie nie rozumiem o co chodzi.

Następnie stworzyłem taki kod który jest widoczny poniżej, ale render następuje dwukrotnie i ostatecznie dane się w tabeli w ogóle nie zmieniają.

	const basicClassName = "starWarsApi";

	const api = `https://swapi.dev/api/people/`;
	const [characters, setCharacters] = useState([]);

	useEffect(() => {
		const fetchOtherData = (characters) => {
			characters.forEach((character) => {
				const homeworld = character.homeworld;
				fetch(homeworld).then((response) =>
					response
						.json()
						.then((data) => (character.homeworld = data.name))
				);
			});
			setCharacters(characters);
		};

		const fetchApi = () => {
			fetch(api)
				.then((data) => data.json())
				.then((data) => {
					fetchOtherData([...data.results]);
				})
				.catch((error) => console.log(error));
		};
		fetchApi();
	}, []);

	return (
		<div className={basicClassName}>
			<h1 className={`${basicClassName}__heading`}>Characters</h1>
			<div className={`${basicClassName}__inputsAndBtnsSection`}>
				<FilteringSection
					basicClassName={`${basicClassName}__inputsAndBtnsSection`}
				/>
				<ButtonsSection
					basicClassName={`${basicClassName}__inputsAndBtnsSection`}
				/>
			</div>
			<CharactersTable characters={characters} />
		</div>
	);
} ```

``` function CharactersTable({ characters }) {
	console.log(characters);
	const dataCharacters = characters.map((character) => ({
		checkboxCol: <input type="checkbox"></input>,
		nameCol: character.name,
		bornCol: character.birth_year,
		homeworldCol: character.homeworld,
		vehiclesAndStarshipsCol: [
			...character.vehicles,
			...character.starships,
		],
		statusCol: "",
		actionsCol: "",
	}));

	console.log(dataCharacters);
	const data = React.useMemo(() => dataCharacters, [dataCharacters]);

	const columns = React.useMemo(
		() => [
			{
				Header: <input type="checkbox"></input>,
				accessor: "checkboxCol",
			},
			{
				Header: (
					<p>
						Name <span>Icon</span>
					</p>
				),
				accessor: "nameCol",
			},
			{
				Header: (
					<p>
						Born <span>Icon</span>
					</p>
				),
				accessor: "bornCol",
			},
			{
				Header: (
					<p>
						Homeworld <span>Icon</span>
					</p>
				),
				accessor: "homeworldCol",
			},
			{
				Header: (
					<p>
						Vehicles and Starships <span>Icon</span>
					</p>
				),
				accessor: "vehiclesAndStarshipsCol",
			},
			{
				Header: (
					<p>
						Status <span>Icon</span>
					</p>
				),
				accessor: "statusCol",
			},
			{
				Header: (
					<p>
						Actions <span>Icon</span>
					</p>
				),
				accessor: "actionsCol",
			},
		],

		[]
	);

	const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
		useTable({ columns, data });

	return (
		<table {...getTableProps()}>
			<thead>
				{headerGroups.map((headerGroup) => (
					<tr {...headerGroup.getHeaderGroupProps()}>
						{headerGroup.headers.map((column) => (
							<th {...column.getHeaderProps()}>
								{column.render("Header")}
							</th>
						))}
					</tr>
				))}
			</thead>
			<tbody {...getTableBodyProps()}>
				{rows.map((row) => {
					prepareRow(row);
					return (
						<tr {...row.getRowProps()}>
							{row.cells.map((cell) => {
								return (
									<td {...cell.getCellProps()}>
										{cell.render("Cell")}
									</td>
								);
							})}
						</tr>
					);
				})}
			</tbody>
		</table>
	);
} ``` 

Z góry dziękuję za pomoc!
1

W tym miejscu mutujesz stan bezpośrednio, przez co React nie wie że w tej tablicy coś się zmieniło. Każda zmiana stanu powinna odbywać się tylko przez wywołanie setCharacters.

.then((data) => (character.homeworld = data.name))

Trochę niżej masz niby użycie setCharacters, ale podajesz tę samą tablicę.

setCharacters(characters);

Powyższą linijkę możesz wywalić do kosza, i od razu przy odbiorze danych zmienić stan przy użyciu setCharacters:

.then((data) => setCharacters(prevData =>  prevData.
    map(prevCharacter => prevCharacter.homeworld === homeworld ?{...prevCharacter, homeworld: data.name} : prevCharacter)))

1 użytkowników online, w tym zalogowanych: 0, gości: 1