Let's say I have a hook, useX() that returns some states and functions. I do an API request that returns some (dynamic amount of) strings (for example, "a" and "b").
I want to have a dictionary mapping these strings to instances of useX(), something like: x = {a: useX(), b: useX()}, so I can do actions like x.a.someFunction() or x.a.someState.
I know React doesn't let you call hooks inside loops, so I wonder whether this is even possible at all. Please help!
I think what you're facing is XY problem, you've found a problem and figured out that this is the solution, and you asked your question about the solution, not the original question..
Your problem is that you want to use "Dynamic number of hook calls.
Is this possible? No.
However, is this the solution? still a No
Your solution is basically to use one big hook or multiple hooks to solve your problem.
What's I've understood from your problem though is that you want something like events, in this case, see Redux
Related
I am currently building a simple web element editor with React using Redux. It works as it should work with a small number of elements. I can see though that when the number of elements gets on a two digit scale, it will be frustrating to organize and maintain. The reason is because I have to pass [IDs and names (local to the function data), State, Actions] to the function I call which in turn filters the arguments and calls other functions with the right arguments etc. I think it is more ifs than it is needed. Can it be done with a function where I can have all the state and the actions, pass it some arguments, choose the correct path and done?
I do not think that providing code will help with this question, you would have see my file system as well to have the whole picture.
I am a junior developer so please forgive me if this is a stupid question or similar. Thank you in advance!
I have started using Fields Array from redux-form, and it uses the index which is a simple integer as keys. But isin't that wrong? I have been testing it out and don't have any issues but read this article which says it could cause issues. So how come this does not become an issue here?
Redux-Form although a great package, not trying to say it isn't, has grown to have many issues and anti-patterns. Just take a look at its name Redux-Form, and take a look at this Redux FAQ about keeping form state in redux - it says it is not preferred to keep form state in redux! How about that?
Now let's talk about iterating with indexes and why it is bad. Since you've read the article in your question, I assume you already understand it - It's because it is bad at keeping a unique representation of items, especially if they get moved up and down, old and new. Now that does not mean that it should always be avoided. If you are good at handling indexes and positions, you do not need to worry about that. Redux-Form is not the only package doing this, Formik is as well.
To conclude, using indexes as field arrays is not ideal, you will always be safer with something like uniqid(). But it is not the end of the world either. Redux Form is a highly complex package, and they know how to handle their state, so we can assume they know how to handle their indexes as well.
I'm trying to use Axios with TypeScript in a React component. The following suggested answer in a different thread seems to provide some pretty good guidance:
https://github.com/axios/axios/issues/1510#issuecomment-385939438
However, something about the suggested approach doesn't appear to be translating well for my component implementation. After fiddling around with this implementation, it seems that I'm still unclear on how state should be initialized in the constructor for this scenario, and possibly within the request().then() handler as well. Here's my current code:
https://github.com/git-it-2020/random/blob/master/axios-react-typescript
The code is fairly simple but doesn't currently compile. Can you provide some guidance on what I'm missing here?
One pattern I've seen recommended is to use selectors to where possible to hide the shape of the store. That way if you need to update the shape of the store, you should be able to get away with only updating your selectors, and not other parts of the application.
However the same problem arises with the use of models within the state.
As one of many examples, let's assume I'm building a file system in Redux. I have a list of files which can either be a directory or a file.
My store might have a fileList property which contains an array of file ids as well as a files object which maps fileId to a file object.
Let's say I have a list of files and I want to, depending on whether it's a file or directory, have a different Item component (i.e. DirectoryItem and FileItem).
One way to achieve this is to do something like:
{
files.map(file => {
file.type = 'directory' ?
<DirectoryItem key={file.id} ...file /> :
<FileItem key={file.id} ...file />
)}
}
(or I could create a higher-order FileListItem component, for example, that does the check and renders either the DirectoryItem or FileItem)
However this might not be ideal because now my component needs to know the structure of the file object. I might want to add a different type of object (i.e. a shortcut file or shared file) and might decide that a type property isn't how I want to represent my data anymore. As such, I'd need to go and update all my components, etc.
If I were doing this in Backbone, for example, I would've probably chosen to define an isDirectory() function on my model, however that doesn't seem to be the Redux way of doing things.
One possible solution I can think of is creating a FileUtils helper class which exports an isDirectory method and takes a file object as a parameter.
Another option will be creating an isDirectory selector which takes a file id as a prop, doing something like:
(files, props) => state.files[props.fileId].type == 'directory'
If I were to create the selector, I suppose I would need to create a higher-order component to call the selector from.
Just wondering if either approach is recommended in Redux? Am I missing another approach that could help solve this issue?
The functional way of doing things simply prescribes tearing the method off of the object and calling it a function.
The recommended way to call it is to instead of having a this, simply pass a regular parameter. This is not a requirement. You can just use call or apply. That may seem real strange in js, but this may change soon with a new :: operator.
Now, you can give this function anything you like to help it get its data.
In your example
(files, props) => state.files[props.fileId].type == 'directory'
You pass it state (naming mistake there) and props and then use this info to come up with an answer. But you could instead choose to pass it a directory entry object. No need to go fetch it from state.
Note that this makes it very close to a method.
isDirectory = entry => entry.type === 'dir';
Now, because it's not getting state, it isn't selecting anything from state and is therefore not a selector.
However, it's plenty functional in nature. There really is no need or use to make life more complicated than that. Adding a higher order component or trying to shoehorn our problems into a more Redux-y way of doing things is needlessly complicating matters.
Selectors are recommended for selecting state so state usage is not tied to state shape. It's an abstraction layer, separating your mapStateToProps from your reducers.
Selectors are now considered part of the Redux Way, but that wasn't always true. And so, at your discretion, being informed of why something is done the way it is, you can then choose to not use it.
And, at your discretion, you can choose to substitute the current trend with your own version. It is highly recommended to do this, of course after consideration of alternatives.
Often the best solution is the one you come up with yourself. Being the most informed about your problem domain, you are uniquely qualified to formulate a matching solution.
Those who have developed great ideas that all of us feed off of and get inspiration from will probably move on from their viewpoint when something better comes along.
There isn't (and probably shouldn't be) a sacred paradigm. Everything is eligible for reconsideration. Occam's razor dictates that the simplest answer is most likely the right one.
And Redux is very much about simplicity. So to do things the Redux Way is mostly about doing things the straightforward way.
I read about React being very fast. Recently, I wrote an app to test react against angular. Unfortunately I found react performing slower than angular.
http://shojib.github.io/ngJS/#/speedtest/react/1
Here is the source code for react. I'm very new to react. I am sure I'm doing something wrong with my react code here. I find it unusually slow.
https://jsbin.com/viviva/edit?js,output
See if any react experts can find the bottlenecks.
Update 1:
Removed the usage of context.
Better usage of setState.
Better usage of shouldComponentUpdate.
I still can't make it faster than angular or even close to it.
https://jsbin.com/viviva/96/edit?js,output
Update 2:
I made a big mistake by creating 2d arrays in the cell component. So I moved them to a mixin. Now I believe that react is faster than angular in DOM manipulations.
https://jsbin.com/nacebog/edit?html,js,output
Update 3:
My mistake again. I did it wrong which made it faster. After analysis, it was rendering incorrectly. If anyone can help me understand, if this could be any faster. I know react is not good at dealing large arrays. In this scenario, it's dealing with four 3d arrays. https://jsbin.com/viviva/100/edit?html,css,js
React's performance is exaggerated. It's fast enough for most real use cases. Rendering large lists is its main weakness.
Also this always returns true (unless the update is triggered by setState). You need to shallow compare the props.
shouldComponentUpdate: function(nextProps, nextState) {
return this.props !== nextProps;
}
And you should be using props in the places you're using context.
This is a very contrived example in my opinion.
As stated above, you are using context incorrectly.
There is no need for a mixin: the number of columns and rows can and should be passed down as props. create2DArray, getRandomNumber should be declared at the top of your script as simple global functions.
You are setting the state incorrectly. You should never change the state like this this.state.some = 'whatever', you have to use setState
this.setState({ some: 'whatever' });
You're using context incorrectly, the documentation states:
In particular, think twice before using it to "save typing" and using
it instead of passing explicit props.
It's mostly beneficial for passing context objects like currently logged in user or perhaps a redux store. Your app is using context when it should be using props.
You'll need to ensure that shouldComponentUpdate is a meaningful predicate. See https://facebook.github.io/react/docs/advanced-performance.html
If you correct those two things it'll be a better measure of React's performance compared to Angular. At the moment you've got a well tuned Ferrari running against a model T Ford (held together with chewing gum).