Here's a problem that took me embarrassingly long to solve: How do you populate dynamic values into a react-redux-form?
First of all, react-redux-form is not the same as redux-form. They're similar but not the same. The internet is confused about this issue, and that makes googling hard.
Second of all, we're talking about a form driven by Redux. Pre-filling it with default values should be as easy as filling out its Redux state. Right?
Well, forms live in their own reducers that you don't have direct access to. They use a bunch of internal state to mark inputs as dirty and focused and whatnot. It's a mess.
Let's start at the beginning.
A simple react-redux-form
Here's a simple form built using react-redux-form. It has two input fields. When you Submit, it outputs your values to the console.
See the Pen ReactReduxForm - Quick Start by Swizec Teller (@swizec) on CodePen.
Borrowed the code straight from @davidkpiano's official Quick Start example.
Our form starts with a model and a Redux store:
const initialUserState = {
firstName: "",
lastName: "",
};
const store = createStore(
combineForms({
user: initialUserState,
}),
applyMiddleware(thunk)
);
initialUserState
describes the shape of a user and combineForms
creates a special reducer. That reducer takes care of driving the UI for our form and storing values.
You'd think you could add default values to initialUserState
, and you can. Hold that thought… let's make sure we understand react-redux-form first :)
The form itself comes in as a React component using <Control>
elements from react-redux-form.
class UserForm extends Component {
handleSubmit(values) {
console.log(values);
}
render() {
return (
<form model="user" onsubmit="{(values)" ==""> this.handleSubmit(values)}
>
<div class="field">
<label>First name:</label>
<control class="text" model="user.firstName">
</control></div>
<div class="field">
<label>Last name:</label>
<control class="text" model="user.lastName">
</control></div>
<button type="submit">
Submit
</button>
</form>
)
}
}
handleSubmit
is the function we call when a user submits either by pressing the Submit button or hitting Enter. In our case, it prints values to the console.
The render
method uses a <Form>
component from react-redux-form. It comes with all the necessary Redux wiring so we don't have to worry about that.
We use the children of that component to define how it renders. In our case, that's two div
s, some labels, a submit button, and two <Control.text>
components.
<Control.X>
components come with all the necessary wiring for our form to work. They'll handle focus, blur, default values, matching to correct parts of our model and so on. Everything we don't want to worry about manually.
Wonderful 👌
Static versus Dynamic default values
Back to that obvious thought. Why can't you just use initialUserState
to define default values?
You can. As long as your default values are static.
Let me explain.
Your default form values are static, if you know them in advance. Like when you're writing your code. This is pretty rare.
What if you're building an edit form? You can't know values for your form until the user chooses what they're editing.
And that's when trouble begins.
Fill react-redux-form with dynamic default values
@lukeed05 helped me find the solution during livecoding. Thanks, mate.
Here's how you do it:
react-redux-form
comes with a bunch of model actions. Actions its reducer understands. Actions it can use to do special things. Like populate your form.
See the Pen ReactReduxForm - Dynamic Default Values by Swizec Teller (@swizec) on CodePen.
Tap the "Change Defaults" button to pick a new random user. Its name will populate the form, and you can edit to your heart's content.
To make that work, we used a Redux action generator called actions.merge
. It lets us merge the form model with a new set of default values.
First we connect our UserForm
component to Redux.
const mapDispatchToProps = {
setDefaultUser: (values) => actions.merge("user", values),
};
const ConnectedForm = connect(null, mapDispatchToProps)(UserForm);
The usual stuff. Use connect
to connect to Redux, there's no props we need from state, and we use mapDispatchToProps
to add a dispatch function called setDefaultUser
.
setDefaultUser
is a curried application of actions.merge
. Takes a value object and merges it with the user
model in our store.
I wired it to an onClick
callback in this example so you can try it multiple times.
changeUser() {
this.props.setDefaultUser(
randomUsers[Math.floor(Math.random()*randomUsers.length)]
)
}
Another approach you can use is to call this action in componentDidMount
. That gives you true defaults – a form populated as soon as a user sees it.
Happy hacking 🤓
Continue reading about How to populate react-redux-form with dynamic default values
Semantically similar articles hand-picked by GPT-4
- Why react-hook-form is my new favorite form library
- Delightful state management with hooks and Constate
- Update state during render, better explained
- Why you should build a form generator
- Livecoding #25: Adding MobX to a vanilla React project
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️