I am trying to use UseParam to get the id, i am trying to place it inside of my API request however when i console.log it the actual value doesn't go inside rather the text itself.
vesselComponents.js :
function VesselComponents() {
const { id } = useParams();
const api = async () => {
try {
const res = await axios.get(
// here
`http://127.0.0.1:8000/api/maintenance/${id}`
);
return res.data;
} catch (error) {
console.log(error);
}
};
console.log(api);
const { components, error, loading } = useSelector(
(state) => state.components
);
const dispatch = useDispatch();
useEffect(() => {
fetchComponents()(dispatch);
}, [dispatch]);
const getTreeItemsFromData = (treeItems) => {
return treeItems.map((treeItemData) => {
let children = undefined;
if (treeItemData.children && treeItemData.children.length > 0) {
children = getTreeItemsFromData(treeItemData.children);
}
return (
<TreeItem
component={Link}
to={`./info/${treeItemData.id}`}
key={treeItemData.id}
nodeId={String(treeItemData.id)}
label={treeItemData.name}
children={children}
/>
);
});
};
const DataTreeView = ({ treeItems }) => {
return (
<TreeView
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
>
{getTreeItemsFromData(treeItems)}
</TreeView>
);
};
return (
<div className="components-container">
<div className="components-items">
<DataTreeView treeItems={components} />
</div>
<div className="component-detail">
<Outlet />
</div>
</div>
);
}
export default VesselComponents;
This is how the console.log look like :
async () => {
try {
const res = await axios__WEBPACK_IMPORTED_MODULE_3___default().get( // here
`http://127.0.0.1:8000/api/maintenance/${id}`);
return res.data;
} catch (err…
Also if i wanted to make this call rather in my slice how would i go about exporting this specific ID that changes so i can use it there.
This is because you actually log the function, not the return value.
I suppose you want to fetch the maintenance id as the component mounts. I advice you to use useEffect for this case.
import { useEffect, useState } from 'react'; // above the component's class declaration
// and inside your component
const [api, setApi] = useState(null); // null by default
useEffect(() => {
const fetchMaintenance = async () => {
try {
const res = await axios.get(
// here
`http://127.0.0.1:8000/api/maintenance/${id}`
);
return res.data;
} catch (error) {
throw Error(error);
}
});
};
fetchMaintenance()
.then((api) => {
setApi(api);
})
.catch((error) => {
console.log(error);
});
}, []);
And by that you can use the value of api anywhere you like.
For example to log it
useEffect(() => {
console.log(api);
}, [api]);
or to render it on your view
return (
return (
<div className="components-container">
{JSON.stringify(api)}
<div className="components-items">
<DataTreeView treeItems={components} />
</div>
<div className="component-detail">
<Outlet />
</div>
</div>
);
}
Related
for learning purposes I'm creating a CRUD todo list with React and JSON-server. I got stuck with PATCH method, as it only updates data in JSON-server on the first click. I want to update the data with the component's state value.
Service file with requests:
const serverAddress = 'http://localhost:8000';
const collection = 'todoItems';
const fetchAll = async () => {
const response = await fetch(`${serverAddress}/${collection}`);
const todoItems = response.json();
return todoItems;
};
const complete = async (id) => {
const completed = {
completed : true
}
// how to set the 'completed' value in json-server based on item's state?
const response = await fetch(`${serverAddress}/${collection}/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify(completed ),
});
const data = await response.json();
return data;
}
const TodoItemsService = {
fetchAll,
create,
remove,
complete
};
export default TodoItemsService;
Card component which holds all todo items:
const Card = () => {
const [todoItems, setTodoItems] = useState([]);
const fetchAllTodoItems = async () => {
const fetchedTodoItems = await TodoItemsService.fetchAll();
setTodoItems(fetchedTodoItems);
};
useEffect(() => {
(async () => {
fetchAllTodoItems();
})();
}, []);
const handleComplete = async (id) => {
await TodoItemsService.complete(id);
}
return (
<div className='card'>
<CardHeader />
<AddTodoForm onAddTodoItem={handleAddTodoItem} />
<TodoItemsContainer
todoItems={todoItems}
onDelete={handleDelete}
onComplete={handleComplete}
/>
</div>
)
}
export default Card;
TodoItemsContainer component
const TodoItemsContainer = ({ todoItems, onDelete, onComplete }) => {
return (
<div className='todo-items-container'>
{todoItems.length === 0 &&
<div className='empty'>
<img src={NoTodoItems} alt="" />
</div>}
{todoItems.map(({ id, text }) => (
<TodoItem
key={id}
id={id}
text={text}
onDelete={onDelete}
onComplete={onComplete}
/>
))}
</div>
)
}
export default TodoItemsContainer;
TodoItem component
const TodoItem = ({ id, text, onDelete, onComplete }) => {
const [isComplete, setIsComplete] = useState(false);
const handleIsCompleteById = () => {
onComplete(id);
setIsComplete(!isComplete);
};
const handleDeleteTodoItemById = () => {
onDelete(id);
};
return (
<div className={`todo-item ${isComplete ? 'complete' : ''}`}>
<p>{text}</p>
<div>
<TodoItemComplete onComplete={handleIsCompleteById}/>
<TodoItemDelete onDelete={handleDeleteTodoItemById}/>
</div>
</div>
)
}
export default TodoItem;
TodoItemComplete button component
const TodoItemComplete = ({ onComplete }) => {
return (
<button type='button' onClick={onComplete}>
<div className='icon'>
{<SVGComplete />}
</div>
</button>
)
}
export default TodoItemComplete;
From React perspective it works fine, it marks the item as complete based on state, but I also want to reflect todo item's status as complete in my json-server. Does anyone have any tips or can see the mistake?
Simply had to pass the state as the second param in complete service and other functions that handle complete action.
In my NextJS app, I get initial data via getInitialProps;
TvApp.getInitialProps = async (ctx) => {
const res = await axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`)
const data = await res
return { data: data.data }
}
I use that data like this;
export default function TvApp(data) {
return (
<div className={styles.container}>
<h2 className={styles.bigAmount}>
{data.data.thirdScreen[0] && data.data.thirdScreen[0].AMOUNT}
</h2>
</div>
);
}
I also want to update my view in every 10 seconds.
My problem is I cannot set the data previously defined in getInitialProps.
export default function TvApp(data) {
useEffect((data) => {
const timer = setInterval(() => {
axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`)
.then(response => ) //This line should set the data with response
.catch(error => {
console.error(error.response.data);
});
return () => clearInterval(timer);
}, 10000);
}, []);
return (
<div className={styles.container}>
<h2 className={styles.bigAmount}>
{data.data.thirdScreen[0] && data.data.thirdScreen[0].AMOUNT}
</h2>
</div>
);
}
How can I set the data in useEffect?
This is probably a very basic question but I cannot find a way.
You can use sate variable to hold the data if it has to be updated in component
export default function TvApp(props) {
const [data,setData] = useState(props.data);
useEffect(() => {
const timer = setInterval(() => {
axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`)
.then(response =>
setData(response.data);
) //This line should set the data with response
.catch(error => {
console.error(error.response.data); });
return () => clearInterval(timer);
}, 10000);
}, []);
return (
<div className={styles.container}>
<h2 className={styles.bigAmount}>
{data.thirdScreen[0] && data.thirdScreen[0].AMOUNT}
</h2>
</div>
);
}
I'm creating a page that will call my API route to return the value from my collection using MongoDB. But I'm having this error of Objects are not valid as a React child. I don't know why this happening. Can you please help me?
pages/index.js
export const getServerSideProps = async () => {
const res = await fetch('http://localhost:3000/api/listings');
const data = await res.json();
if (!data) {
return {
notFound: true,
};
}
return { props: { data } };
};
const index = async ({ data }) => {
return (
<>
<section className='w-screen h-screen bg-hero-pattern bg-cover bg-no-repeat bg-bottom'></section>
{data.map((prop) => (
<div key={prop._id}>
<h1>{prop.name}</h1>
<h2 className='text-2xl truncate'>{prop.summary}</h2>
<p>{prop.description}</p>
</div>
))}
</>
);
};
pages/api/listings
import { connectToDatabase } from '../../middlewares/mongodb';
export const fetchDbData = async () => {
const { db } = await connectToDatabase();
const data = await db
.collection('listingsAndReviews')
.find({})
.limit(1)
.toArray();
return JSON.parse(JSON.stringify(data));
};
export default async (req, res) => {
const data = await fetchDbData();
res.status(200).json(data);
};
I'm working with tmdb api, I've been using react's useEffect and useContext for minor stuff and it works. I decided to use the api and it has been going into this infinite loop anytime I try to run it. I'm using axios with useEffects and useContext. Below is the component calling axios
enter image description here
function MovieList(props) {
useEffect(() => {
const getMovies = async () => { };
try {
const response = await axios.get(movieUrl, { cancelToken: source.token });
addMovies(response.data.results);
// setLoading(false)
} catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
} else {
// handle error
throw error
}
}
getMovies();
}, []);
return (
<React.Fragment>
<div className="container-fluid pl-5">
<h2 className="white mt-4">{pageTitle}</h2>
<div className="row">
{movies.map((movie) => {
return <Movie key={movie.id} movie={movie} />;
})}
</div>
</div>
</React.Fragment>
);
}
My code goes into an infinite loop and it's driving me crazy.
And my context code is found below:
export const MovieProvider = (props) => {
const [isFav, setIsFav] = useState(false)
const [movies, setMovies] = useState([]);
const [filtered, setFilteredMovies] = useState([])
const addMovies = (res) => {
setMovies([...res]);
}
const addFavMovies = (res) => {
if(res){
setMovies([...res]);
}
}
const addFilteredMovies = (res) => {
setFilteredMovies([...filtered, res]);
}
return (
<MovieContext.Provider value={{
fav: [isFav, setIsFav],
movies, addMovies, addFavMovies,
filtered, addFilteredMovies,
}}>
{props.children}
</MovieContext.Provider>
)
}
I have problem with load data to component after click on button.
I use getInitialProps to first load data on page.
How to load new data and past them to {data} after click?
export default function Users({ data }) {
const fetchData = async () => {
const req = await fetch("https://randomuser.me/api/?gender=male&results=100");
const data = await req.json();
return { data: data.results };
};
const handleClick = (event) => {
event.preventDefault();
fetchData();
};
return (
<Layout>
<button onClick={handleClick}>FETCH DATA</button>
{data.map((user) => {
return (
<div>
{user.email}
<img src={user.picture.medium} alt="" />
</div>
);
})}
</Layout>
);
}
Users.getInitialProps = async () => {
const req = await fetch(
"https://randomuser.me/api/?gender=female&results=10"
);
const data = await req.json();
return { data: data.results };
};
Thank a lot for help!
Use useState with the default value being the data you initially retrieved via getInitialProps:
import { useState } from 'React';
export default function Users({ initialData }) {
const [data, setData] = useState(initialData);
const fetchData = async () => {
const req = await fetch('https://randomuser.me/api/?gender=male&results=100');
const newData = await req.json();
return setData(newData.results);
};
const handleClick = (event) => {
event.preventDefault();
fetchData();
};
return (
<Layout>
<button onClick={handleClick}>FETCH DATA</button>
{data.map((user) => {
return (
<div>
{user.email}
<img src={user.picture.medium} alt="" />
</div>
);
})}
</Layout>
);
}
Users.getInitialProps = async () => {
const req = await fetch('https://randomuser.me/api/?gender=female&results=10');
const data = await req.json();
return { initialData: data.results };
};
Sidenote: Times have changed and it would seem that user1665355 is indeed correct:
Recommended: getStaticProps or getServerSideProps
If you're using Next.js 9.3 or newer, we recommend that you use
getStaticProps or getServerSideProps instead of getInitialProps.
These new data fetching methods allow you to have a granular choice
between static generation and server-side rendering.
import { useState } from 'React';
export default function Users({ initialData }) {
const [data, setData] = useState(initialData);
const fetchData = async () => {
const req = await fetch('https://randomuser.me/api/?gender=male&results=100');
const newData = await req.json();
setData(newData.results);
};
const handleClick = (event) => {
event.preventDefault();
fetchData();
};
return (
<Layout>
<button onClick={handleClick}>FETCH DATA</button>
{data.map(user => {
return (
<div key={user.login.uuid}>
{user.email}
<img src={user.picture.medium} alt="" />
</div>
);
})}
</Layout>
);
}
Users.getInitialProps = async () => {
const req = await fetch('https://randomuser.me/api/?gender=female&results=10');
const data = await req.json();
return { initialData: data.results };
};
I would like to list my notes about George's code. At least, it should pay attention to them.
First of all, it should attach any key to a div element otherwise a warning will have appeared in the browser console. Here is an article about using keys: https://reactjs.org/docs/lists-and-keys.html#keys
As well, the keyword return can be removed from the fetchData function that doesn't return a response.
It is recommended to use getStaticProps or getServerSideProps now. https://nextjs.org/docs/api-reference/data-fetching/getInitialProps