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.
Related
I couldn't find a proper answer for that, but I'd like to know if it is a bad practice or a recommendation related to using the matching state variable to the state setter function.
setMyState(!myState);
It's common to see this approach mainly to change the boolean values to the opposite. So I thought it was normal to do it.
But I'm getting this error from Sonar:
React state setter function should not be called with its matching state variable
When the setter function is called with the state variable as a parameter, nothing will happen. This can happen by mistake when attempting to reset a default value or invert a boolean, among others.
The fix is simple, but I've never seen any warning or official information related to it.
Does anyone?
can I use Use state instead of redux?
Can I Manage all the state by use state ?
This question has a long and complicated answer, but I would suggest the first port of call would be reading up on the redux docs about how you might want to organise the state within your application.
TL;DR, it entirely depends on your situation, take a look here
Both are valid, but both have cases where they are better to be used, for example if you have a state you want to manage one level below, and is not used by other components on different hierarchy, then passing the state and it's handler as a prop is the better solution.
But some cases are more complex and require a lot of passing down of a prop through the components until it reaches the child that actually uses it, and. the parents of that child do nothing but pass it down, that is a smell of bad code.
Here it is beneficial to have it in a global state where the child can access it directly, without needed all of its predecessors to pass it down as a prop (also known as prop-drilling). Another case where this is useful is when multiple components need to access the same state, in different part of the system. It would be much cleaner to have it stored in a global state available for every component that requires it.
TL;DR, depending on your case, one solution is better than the other. Assess your situation case-by-case.
This question already has answers here:
What's the difference between "super()" and "super(props)" in React when using es6 classes?
(10 answers)
Closed 4 years ago.
Can someone please tell me why we need to pass in props to constructor() and super(). I've read a lot of questions regarding this, and also a lot articles too. All saying you should pass in props to constructor and super so that you may access this.props.....
All of my code still works if i do not pass in props to constructor or super. And I can't see any scenario where this would change. Unless i wanted to console log this.props, which could be achieved by console logging this anyway.
Also on a side note, half of the developers I've spoken to, do pass in props, and the other half do not, because they feel they don't need to, yet aren't exactly sure why this happens.
Can anyone shed some light on this for me please?
Thanks
The only reason someone needs to pass props is if you want to do something with them in the constructor. Maybe you want to do some computation on props in the constructor -- I'm not sure you can just do that outside of the constructor even though you have access to props without the constructor.
The documentation gives the example of assigning initial state utilizing props in the constructor. In the case of components with local state, this is a good use case for passing props to the constructor.
Additionally, this this SO answer sheds some light on why you need to pass props to super in ES6.
Though, much of this can be disregarded in the sense that you could just not pass props to constructor and initialize your local state without it due to class properties of state and props. Check this Hacker Noon article going through some of the "use cases" of constructor and their alternatives. One thing to point out is that the author mentions that Babel transpiles your code for you to add a constructor -- you just don't see it. Ultimately, I suppose if it is a matter of removing the constructor, you can do it as a matter of preference as also pointed out by Dave Ceddia. Removing the constructor, though, seems to have the added benefit of removing boilerplate and keeping code a bit cleaner.
Ultimately, the author concludes:
We’ve seen that for setting our initial state, we no longer need a constructor (or any other instance property for that matter). We also
don’t need it for binding methods to this. Same for setting initial
state from props. And we would most definitely never fetch data in the
constructor.
Why then would we ever need the constructor in a React component?
Well… you don’t.
[However… If you find some obscure use case where you need to
initialize something in a component, both client-side and server-side,
you still have an out. There’s always componentWillMount. Internally,
React calls this hook right after “newing” the class (which calls the
constructor) on both the client and the server.]
So I maintain that for React components: The constructor is dead, long
live the constructor!
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.
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.