I have following hook:
const [textToFront, setTextToFront] = useState('');
When I call setTextToFront I see that old state was cleared, I want to implement simple thing, I just want to create one big String in the hook and display. How to store and add new coming state to old state?
Try
setTextToFront(`${textToFront}${newAppendedText}`);
Related
I'm trying to build react (with next.js) based chat client using the LiveChat CustomerSDK API.
I currently use a useEffect hook to initialize and then store the object with a useState hook.
const [customerSDK, setCustomerSDK] = useState();
useEffect(() => {
const sdk = CustomerSDK.init(config);
setCustomerSDK(sdk)
}, []);
But I am wondering whether useState is the best way for the customerSDK object, since it doesn't need to trigger a re-render. Therefore I also considered using useRef instead or maybe just storing it in the window object. But neither "feels right".
I have to consider that I need to access the customerSDK object to set the listeners (e.g. customerSDK.on('connected', ...) and also for example sending messages (customerSDK.sendEvent(...)
Is there a recommended/preferred way to approach a situation like this?
Theres another option if you know you only have 1 project accessing it, simply put it in a file and export it, then import this everywhere you need it. If it needs no context (i.e. react state) from your components, why have it stored in a component at all?
const sdk = CustomerSDK.init(config);
export default sdk
Then import that where you need it. It will act as a singleton.
I'm building an app in React Native,
and I am trying to understand if I need to use useState & useContext to export a user info object,
or I can just get the object from the script, change it, and it will be changed to all the other scripts.
(or if there is a better way to do it so)
Thanks in advance :)
If you update data in your component, always use useState.
Furthermore if you store an array or an object into your state, it's a good practice to update the array/object, and then update your state with a spread operator (this will create a new array/object, and fired your useEffect and UI)
Example :
If you do a simple :
const [stateArray, setStateArray] = useState(["foo"])
stateArray[0] = "new foo"
All the components that consume the stateArray[0] will not update and continue to display a simple foo
This is caused becaused this update doesn't triggered a refresh as you're array isn't update, but one of it's component (not detect by React).
If you want an update, you need to do :
const [stateArray, setStateArray] = useState(["foo"])
stateArray[0] = "new foo"
setStateArray([...stateArray])
This will create a new array, and as such, triggered a new render of your component.
And the same logic applied for object, if you only update one of its value, there will be no update, you need to create a new object :
Example :
const [stateObject, setStateObject] = useState({foo: "foo"})
stateObject.foo = "new foo"
setStateObject({...stateObject})
I have a little question. Let's assume this code
const [ChatDetailsRender, setChatDetailsRender] = useState([]);
//ChatDetailsRender it s equal= {10,20}
array=[1,2,3,4]
array.forEach((nr)=>{
setChatDetailsRender();
//here some code to add the array for each value in useState})
This is some simple example about what i wanna do and i have some difficulties because i also have some database calls. Everything looks fine but how can i update ChatDetails useState without overwriting data? like just merge these 2 arrays. Sorry, i think this questions was already here but all i can find it's examples with objects in useState, and my example contains just an simple array. Thanks.
You can concat the new value to the existing value while updating and use callback approach to set state.
const [ChatDetailsRender, setChatDetailsRender] = useState([]);
//ChatDetailsRender it s equal= {10,20}
array=[1,2,3,4]
setChatDetailsRender(previousChatDetails => previousChatDetails.concat(array));
We may have
const [data, setData] = useState([]);
but what if we need to set the initial state to some complicated data structure, such as an array of 360 objects, each other representing the initial amount, the monthly contribution, the interest earned, and the final monthly balance, just like how we calculate the compound interest or mortgage. How could we set this complicated data structure up?
How is using an IIFE:
const [data, setData] = useState( (function() {
const obj;
// set up the object
return obj;
}()) );
?
I think one precaution is we don't want to run the loop every time the function component gets called.
The most effective way is to use a useEffect hook. I'll rapidly explain how it works:
useEffect(()=>{
//here you can do your computation
let myFirstField=...;
let mySecondField=...;
setData({
one: myFirstField;
two: mySecondField;
});
},[]) //putting these "empty array" after use effect ensure that use Effect is called only after "onMount" (at the beginning and not at every refresh)
I want you to notice a thing. Use state hooks aren't like normal state in components. You can't set only a field when you want to change it, but you need to reset the whole state.
Said this, use effect will initialize your state in the way you want. Inside this method you can also run axios request or whatever you want, just remember to handle what the UI is showing accordingly (for example if you perform an axios request, show a spinner for the user to understand that the page is loading)
You can use Lazy initial state to initialize your data.
I've just started using Recoil on a new project and I'm not sure if there is a better way to accomplish this.
My app is an interface to basically edit a JSON file containing an array of objects. It reads the file in, groups the objects based on a specific property into tabs, and then a user can navigate the tabs, see the few hundred values per tab, make changes and then save the changes.
I'm using recoil because it allows me to access the state of each input from anywhere in my app, which makes saving much easier - in theory...
In order to generate State for each object in the JSON file, I've created an component that returns null and I map over the initial array, create the component, which creates Recoil state using an AtomFamily, and then also saves the ID to another piece of Recoil state so I can keep a list of everything.
Question 1 Is these a better way to do this? The null component doesn't feel right, but storing the whole array in a single piece of state causes a re-render of everything on every keypress.
To Save the data, I have a button which calls a function. That function just needs to get the ID's, loop through them, get the state of each one, and push them into an Array. I've done this with a Selector too, but the issue is that I can't call getRecoilValue from a function because of the Rules of Hooks - but if I make the value available to the parent component, it again slows everything right down.
Question 2 I'm pretty sure I'm missing the right way to think about storing state and using hooks, but I haven't found any samples for this particular use case - needing to generate the state up front, and then accessing it all again on Save. Any guidance?
Question 1
Get accustomed to null-rendering components, you almost can't avoid them with Recoil and, more in general, this hooks-first React world 😉
About the useRecoilValue inside a function: you're right, you should leverage useRecoilCallback for that kind of task. With useRecoilCallback you have a central point where you can get and set whatever you want at once. Take a look at this working CodeSandbox where I tried to replicate (the most minimal way) your use-case. The SaveData component (a dedicated component is not necessary, you could just expose the Recoil callback without creating an ad-hoc component) is the following
const SaveData = () => {
const saveData = useRecoilCallback(({ snapshot }) => async () => {
const ids = await snapshot.getPromise(carIds);
for (const carId of ids) {
const car = await snapshot.getPromise(cars(carId));
const carIndex = db.findIndex(({ id }) => id === carId);
db[carIndex] = car;
}
console.log("Data saved, new `db` is");
console.log(JSON.stringify(db, null, 2));
});
return <button onClick={saveData}>Save data</button>;
};
as you can see:
it retrieves all the ids through const ids = await snapshot.getPromise(carIds);
it uses the ids to retrieve all the cars from the atom family const car = await snapshot.getPromise(cars(carId));
All of that in a central point, without hooks and without subscribing the component to atoms updates.
Question 2
There are a few approaches for your use case:
creating empty atoms when the app starts, updating them, and saving them in the end. It's what my CodeSandbox does
doing the same but initializing the atoms through RecoilRoot' initialState prop
being updated by Recoil about every atom change. This is possible with useRecoilTransactionObserver but please, note that it's currently marked as unstable. A new way to do the same will be available soon (I guess) but at the moment it's the only solution
The latter is the "smarter" approach but it really depends on your use case, it's up to you to think if you really want to update the JSON at every atom' update 😉
I hope it helps, let me know if I missed something 😊