I'm using React with Flow. If I forgot to set some requiring props when rendering, Flow gives me error so I can prevent the problem.
However Flow is not actually working on runtime. So if the value that I used were treated as number wasn't number, Flow can't catch this. For example, if the value was coming from somewhere else, like server side and if it was string, but Flow just treated as number so eventually I will get some errors in runtime.
But PropTypes works in runtime, so in the same case I'll get the error message that PropType expected number but actually it was string.
It's also possible to happen when the API were changed and returning data is different. It could undefined or whatever, possibly not actual value I expected.
So I'm using Flow and PropTypes both actually, however I searched on about using both together, but couldn't find any related informations.
Instead, all I found was just "Flow" replaces "PropTypes". I don't think so, I already mentioned about difference between these two. These two works totally different and each of them have so many good benefits to use, so combine them will have nice synergy, I think.
However now I'm using both, I have to define types for props and also define propTypes and defaultProps always, and it makes my code actually pretty long and takes lots of time just make single component.
Should I stop using Flow and PropTypes together? I think Flow is better than PropTypes, there were so much benefits when using static type checker so I want to keep using it. Also there's nice VSCode support for Flow, but not proptypes.
If I use Flow, is PropTypes doesn't needed? Any advice will appreciate it.
Flow allows you provide types for anything.
PropTypes is just for component's props so it cannot help with typing variable or method. It even does not have easy way for tyyping callback props. You will need to describe custom validator.
Also PropTypes works on per-prop basis. You cannot describe independent subsets of props. E.g. "having field NAME is required only if nickname is empty". I agree that this sounds not really helpful with this example. But it still means flow is more flexible.
And btw having typecheck in production is bad idea anyway - it would lead to performance penalty. At the same time most type issues will already be caught. While it still does not save you from issues in logic - so you will need to test that with manual/acceptance/integration tests.
Related
I am currently building a Tetris game on React just to practice hooks (used to develop in class components back in the day, kind of left React for a while and yesterday I decided to use it once again).
The game is working perfectly well, and it behaves as expected on each and every situation, however, there is a constant warning related to using a function within useEffect without it being a dependency.
To clarify - I have a useEffect function that all it does is call an updateFunction and is dependent just on the x and y coordinates of the moving Tetris block. The update function updates the state of the board whenever the position of the shape changes.
I know that React re-creates functions on each and every render, but giving a useCallback to the update function would cause it to be re-created endlessly (as then, the complier would ask me to make it dependent on the board state, thus each time it updates the board, it'll be forced to be re-created once again), and this causes an infinite loop of rendering.
Is it really necessary to put every function within useEffect as a dependency, even if said functions only causes a visual rendering to show the current state of the game?
You can always put whole function inside useEffect and you want get this error and problem
Someone just asked the similar question, and my answer is there, React won't let me use `useEffect` in a completely reasonable way
The answer to your question is that, no you don't have to, if the warning doesn't bother you, and your code is still working, then move on.
Otherwise you can try to find a way to disable this linter, or ask yourself why not to meet all the dependency requirement.
It's best to think of the effect dependencies as "correct" or not, and not try to tailor them to achieve some specific behavior. (The vast majority of the time anyway)
This means that if an effect uses a value that could possibly change, then it's declared as a dependency. Sometimes you app works fine if your dependencies are "incorrect" because elsewhere you can guarantee a value is constant. But this is more about maintaining the application than having it work currently.
Later if you change how one of the dependencies works in a refactoring, then the effect now may need to re-run and doesn't leading to strange and hard to diagnose bugs like stale values where you can't tell where they come from.
If this leads to cumbersome hooks with huge dependency arrays that infinite loop themselves, then it's an indication that logic is messy and needs to be refactored, split into multiple effects, rethink how the data flows through your hooks, etc.
It's hard to advise specifically without seeing your code. But in your case it seems like you could make the "update function" take arguments instead, which means it could then be completely static. Or if you did use useCallback that depends on x,y then it would regenerate when those change, but you probably have a lot of logic to run when those change, so that's probably expected.
Summary:
I would advise you to take the warnings of eslint-plugin-react-hooks seriously, and clean your code until it passes. In the long wrong, in a large and complex application, it really helps keep things clean.
There are very rare exceptions that come up when doing non standard things, but it's worth it to try your best on this before resorting to ignoring those warnings.
I'm working on a part of a React app in which a high-level component creates and passes certain props down through a few layers of components that don't use them to a final component that does.
When validating props with propTypes, is there a good reason to list these props to be checked at every level, going down through the layers? Or is it acceptable to check them only in the final component that uses them?
It seems to me that the former method is redundant; the latter seems to make more sense to me, but I'm curious if there is a reason why I ought to do the former. I haven't seen any discussion on it, which could mean it's an unimportant question, but I'd be interested to know.
I agree with you about if you use props only for dril down for children in the tree, it can be done only once at the leaf components, where you realy use this data. I recently find out that one more place is important for props validation: the components which fetch data from out of app scope, such as backend, because sometimes the structure of the data changes or the data types, then it will be dificult to find which part is broken without props validation.
As a react web app gets complex, some components have a number props, which is less readable, harder to expect what this component does, and tedious to add lots of prop types checks and pass props from top-most component to bottom. This is mostly caused by passing flux/redux actions and stores passed from top to bottom.
Is there a great way to reduce the number of props passed in?
There are two solutions I thought of, which are not perfect:
Pass props with a spread operator {...props}. This does reduce writing a number of props and prop type checks, but there may be conflict in naming, so the names of actions/stores should be unique. Another downside is to be extra careful of what props to pass or not to avoid side effects.
Wrapping the component with a container which directly connects actions/stores to the component, in an hoc-fashion. For example, react-redux's connect() can be used. This is cleaner and simpler than Solution #1, but it's hard to write component tests if the component contains a container because of a Redux error.
One example of the error is
Invariant Violation: Could not find "store" in either the context or props of "Connect(Header)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Header)".
You've described two approaches and their pros and cons pretty well. I'll add a few design considerations to what you've said.
Approach #2 is my preferred approach. Reducing the amount of props passing through the components avoids complexity. There are ways to test components without triggering that error, but I think that deserves its own separate Stack Overflow question, to honest. For now, I'll just say look into shallow rendering, and consider whether you really need to just do unit testing here vs integration testing. If you will also be creating automated tests in something like Selenium, then that can serve as your integration testing, perhaps.
Approach #1 can be improved by making scrupulous use of PropTypes to validate what is being passed through. It's reasonable to leave out the PropTypes checking on the middle components that are just passing ...props through, but the end components (components that actually use the props instead of just passing through) should have really stringent PropTypes declarations. Use Shape instead of Object. Use ArrayOf instead of Array, and basically take all opportunities to be specific in your PropTypes declarations.
Regarding your concern about name conflicts, it sometimes helps to group props together as members of one object and pass that object as a single prop. If the props are conceptually related or have a single destination component, this makes some sense. I still greatly prefer just having more container components (approach #2) since it causes less information to flow through props. And writing good PropTypes for objects with nested members takes a little more time and yields warning messages that take longer to troubleshoot.
People sometimes forget about .state after they start using Redux/Flux, with some purists preferring to send and receive everything through the store. The elegance of the stateless component declaration further biases me against adding .state to a component. But .state is great for tracking ephemeral things like animations and tooltip visibility. Not everything needs to be in the store and pass through props.
I would find it convenient if one of two closely related features were possible to do in React, purely for convenience/syntactic sugar since I know I can do what I want without them, it's just a little uglier/slower. I suspect neither can be done, so rather then write two separate questions that are nearly identical I'm asking about both in this question so you can crash my dreams all at once :)
I've found myself wanting a convenience feature a few times, some way of storing in props a little more knowledge about what props are set to avoid having to write as many helper methods.
To use my most recent example I have two props errorEvaluator and warningEvalutator are functions that check rather a data set should be marked with warning or error state. They both have default props which always return false if an evaluation isn't provided, so I don't have to constantly do null checks in code.
I now want to know if no warning or error evaluator was provided, if so I won't offset everything to make space for the warning/error icon that will never be used, I can't just check for the funcitons being undefined since I use defaultProps. What I'd like is one of two quickconvenience options for checking if these values weren't set by the operator. So something like:
some function that checks rather a prop was passed by user, as opposed to being set by default props, I could call to find out rather there was a value set.
Some way to do quick modification of props whenever a component updates where I can set some showIcon prop if both evaluators are undefined, then set the evaluators to my default always-false evaporators; without having to resort to lifecycle methods which somehow feel like overkill.
Do either of these, or some equivalent quick way of doing such a check exist?
The cleanest option I know works is to not use default props and instead have methods that return my evaluators, returning default evaluator if none is passed, for when I want to use an evaluator, then checking for undefined evaluator in props when I want to know if an evaluator was provided. That works, I'm just wondering if there is some quicker or cooler syntactical sugar I'm not aware of?
For point 1: you can't check whether a prop was passed in or set by default, as doing that would defeat the entire point of having default props. If you want to be able to tell whether a prop was passed in or not, you must not use a default prop and check for undefined.
As for point 2: Not only is there no way to do that, but you should never change props from within the component that receives them. That's just against the way that React works. A component should take its props and handle them. If some value or UI element is an "output" of a component and computed from its props, it should not be a prop of that component. If you need to detect when props change, then lifecycle methods aren't overkill, they are the right way to do that.
Since you know which functions are the default ones, you can check for them explicitly. You could use an equality comparison:
if(this.props.errorEvaluator === this.defaultErrorEvaluator) {
// Set up styles to exclude formatting
}
You'd need to go slightly out of your way to ensure that you always used exactly that evaluator, and that the caller didn't get their hands on it, but that shouldn't be hard.
I'm fairly new to react, and really enjoying it. In creating components, is there a good rule of thumb (or simple generalization) to consider when deciding if a component should manage it's own state or not.
As example (only as example), an input that gets different classes added based on state, like 'hover', or 'not empty'...
Would it be better to create a component that manages those states internally or just handle that wherever I'm rendering an input?
I know this question may be 'primarily opinion based', but I'm hoping to get a general feel for how to think about it.
Thanks in advance,
-Ted
This is a constant internal battle that you'll just decide on down the line and you're right that it's primarily opinion based (meaning no answer will be correct). However, I can share my own experience and the process I take to decide on how to split the logic of my components.
I think of these things:
How will having/not having that piece of logic affect unit tests? If the component would need too much setup to be tested, then I move some logic into it and away from a parent Container component.
How often will I reuse the component? If it's many many times, then I look at the types of Container components that would render it and, again, if it seems like too much boilerplate is needed, then move the logic.
Does the value change through its own behavior or based on outside queues? In your example of the hover, the behavior changes due to its own behavior so it feels like the className (a prop of itself) is reacting to the component itself.
Most importantly, do you benefit from removing the logic and placing it in the Container? If you think that other component could benefit from knowing the hover state of your input field, then you may want to put the logic in the container. Otherwise you're abstracting away too much.
Application state management libraries such as Redux will often suggest to use their libraries as little as possible and instead rely on internal state of the component. I mention this because as you figure out where to put your logic, you have to think that about the end goal, which is usually to create a web application, with multiple components working together. Abstract too little and you end up creating non-reusable components. Abstract too much and you have tons of boilerplate and configuration lying around that could be trimmed by using internal state.
Zeke has some absolutely great points. I'd just like to add my own guideline, which is:
If the behavior of the component is the same, no matter where it's used, and is not tied to the behavior of the app/environment at large, then state should be internal
otherwise, manage state elsewhere and pass in props