Passing a JSON as prop in component React JS - reactjs

I have a component with another child component and I am passing a JSON state variable of the parent component as prop to the child component, but when I modify the JSON in the child component the state variable of the parent is been modified too. It doesn't have sense beacuse it just happens with JSON props, but if i use strings, numbers or arrays it works good and child state variables are just modified.
These are my components:
class Child extends React.Component{
constructor(props){
super(props)
this.state={
test2: this.props.data,
}
this.changeTextField = this.changeTextField.bind(this)
}
changeTextField(e){
let data = this.state.test2
data['name'] = e.target.value
this.setState({test2: data})
}
render(){
return(
<div>
<input type="text" value={this.state.test2['name']} onChange={this.changeTextField}/>
</div>
)
}
}
class Parent extends React.Component{
constructor(props){
super(props)
this.state={
test: {name: "hola"},
editing: false,
}
this.edit = this.edit.bind(this)
this.cancel = this.cancel.bind(this)
}
edit(){
this.setState({editing: true})
}
cancel(){
this.setState({editing: false})
}
render(){
return(
<div>
{(this.state.editing) ?
<React.Fragment>
<Child data={this.state.test}/>
<button onClick={this.cancel}>cancelar</button>
</React.Fragment>
:
<React.Fragment>
<h1>{this.state.test['name']}</h1>
<button onClick={this.edit}>edit</button>
</React.Fragment>
}
</div>
)
}
}
$(document).ready(function(){
ReactDOM.render(<Parent/>, document.getElementById("app"))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
<script src="parent.jsx" type="text/babel"></script>
</body>
</html>

This is how JavaScript works with Objects. They are always passed by reference and the others (strings, booleans, numbers as you mentioned) are primitives meaning they are immutable.
There are many amazing answers on SO already regarding these:
JavaScript by reference vs. by value
Is JavaScript a pass-by-reference or pass-by-value language?
How do we get around this?
In your snippet, where you say data['name'] = e.target.value you are still mutating the state object, which is surely a Not To Do in React. You can read upon Power of not mutating content in React Docs.
You could create a copy of the test2 and choose to mutate that instead:
const data = {...this.state.test2};
data['name'] = e.target.value
But there is a chance that this function gets called programatically, this will run into an error because setState is async. Instead it gives us a functional version to deal with:
this.setState(prevState => ({
test2: {
...prevState.test2,
name: value,
}
}));
Full Demo:
class Child extends React.Component{
constructor(props){
super(props)
this.state={
test2: this.props.data,
}
this.changeTextField = this.changeTextField.bind(this)
}
changeTextField(e){
const value = e.target.value
this.setState(prevState => ({
test2: {
...prevState.test2,
name: value,
}
}))
}
render(){
return(
<div>
<input type="text" value={this.state.test2['name']} onChange={this.changeTextField}/>
</div>
)
}
}
class Parent extends React.Component{
constructor(props){
super(props)
this.state={
test: {name: "hola"},
editing: false,
}
this.edit = this.edit.bind(this)
this.cancel = this.cancel.bind(this)
}
edit(){
this.setState({editing: true})
}
cancel(){
this.setState({editing: false})
}
render(){
return(
<div>
{(this.state.editing) ?
<React.Fragment>
<Child data={this.state.test}/>
<button onClick={this.cancel}>cancelar</button>
</React.Fragment>
:
<React.Fragment>
<h1>{this.state.test['name']}</h1>
<button onClick={this.edit}>edit</button>
</React.Fragment>
}
</div>
)
}
}
$(document).ready(function(){
ReactDOM.render(<Parent/>, document.getElementById("app"))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
<script src="parent.jsx" type="text/babel"></script>
</body>
</html>

Related

why hexadecimal codes don't display in reactjs

👍 and 👎 codes work in plain html. How do I get them to work in react?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Like Click</title>
<script src="react/react.js"></script>
<script src="react/react-dom.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
</head>
<body>
<div id='container'>
</div>
</body>
</html>
<script type='text/jsx'>
class Like extends React.Component{
constructor(props){
super(props);
this.state={liked:false};
}
toggle(){
this.setState({liked: !this.state.liked});
}
render(){
var name = this.props.name;
var txt = this.state.liked ? 'Like':'Unlike';
var weight = this.state.liked ? 'bold':'normal';
var color = this.state.liked ? 'green':'red';
var thumb = this.state.liked ? "👍":"👎";
return(
<div>
<span style={{fontWeight:weight,color:color}} onClick={this.toggle.bind(this)}> {name} {thumb}{txt} </span>
</div>
);
}
}
ReactDOM.render(
<Like name='Java' />,document.getElementById('container')
);

where does input to function come from

We have the following react html. In the callback function filterList() we have as a parameter 'input' filterList(input). Where does this object come from? Is this coming from the onClick event? what other objects are available?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Filtered List</title>
<script src="react/react.js"></script>
<script src="react/react-dom.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
</head>
<body>
<div id='container'></div>
<script type="text/jsx">
class FilteredList extends React.Component {
constructor(props) {
super(props);
var allItems = [ "anteater", "bear", "cat", "dog", "elephant", "fox" ];
this.state = { initialItems: allItems, currentItems: allItems };
}
filterList(input){
var updatedList = this.state.initialItems;
updatedList = updatedList.filter(function(item){
return item.search(input.target.value) !== -1;
});
this.setState({currentItems: updatedList});
}
render(){
console.log(this);
return (
<div className="filter-list">
<input type="text" placeholder="Filter" onChange={this.filterList.bind(this)}/>
<List items={this.state.currentItems}/>
</div>
);
}
};
class List extends React.Component {
render(){
return (
<ul> { this.props.items.map(function(item) {
return <li key={item}>{item}</li> }) }
</ul>
)
}
};
ReactDOM.render(<FilteredList/>, document.getElementById('container'));
</script>
</body>
</html>
Input has an onChange listener when something happens it gives parameter to the function of the onChange.
Without this parameter the onChange parameter can't know what changed :)
Few words: yes it comes from onChange
More on here https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onchange

How to Render React App in Custom HTML5 Element instead div[id=root]

I am at requirement that I have build some ReactJs components but need to use them inside Custom HTML tags( just like normal tags )
I am trying to create a "Board" component which just displays a text "In board...". Now I am trying to use this in my HTML page as .
My board.js file:
class Board extends React.Component {
render() {
return (
<div>
<div className="status"> In board.... </div>
</div>
);
}
}
My HTML page:
<html>
<head>
<script src="https://unpkg.com/react#16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js" crossorigin></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<script src="board.js" type="text/babel"></script>
</head>
<body>
<Board />
</body>
</html>
tag must be treated like an HTML tag and should load React component and display the text "In board....".
In your case, you have to create using customElements API. You can use customElements.define Method to create your own but name should be hyphen separated.
window.customElements.define('message-board',
class extends HTMLElement {
constructor() {
super();
this.innerHTML = '';
}
}
);
Below is the Working Example.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Board </title>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script>
window.customElements.define('message-board',
class extends HTMLElement {
constructor() {
super();
this.innerHTML = '';
}
});
</script>
<script type="text/babel">
class Board extends React.Component {
render() {
return (
<div>
<div className="status"> In board.... </div>
</div>
);
}
}
ReactDOM.render(
<Board />,
document.getElementsByTagName('message-board')[0]
);
</script>
<script>
</script>
</head>
<body>
<message-board />
</body>
</html>
Creating a custom element and rendering React component to this custom element can be done as below. Assuming "Board" is an React component.
window.customElements.define('message-board',
class extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
ReactDOM.render(<Board />, this);
}
});
A working solution to convert a simple React component to HTML Custom element
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Board </title>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script crossorigin src="https://unpkg.com/#webcomponents/webcomponentsjs#2.0.3/custom-elements-es5-adapter.js"></script >
<script type="text/babel">
class Board extends React.Component {
render() {
return (
<div>
<div className="status"> In board.... </div>
</div>
);
}
}
window.customElements.define('message-board',
class extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
ReactDOM.render(<Board />, this);
}
});
</script>
</head>
<body>
<div>
<message-board />
</div>
<div>
<message-board />
</div>
</body>
</html>

React without npm

How to import js file with code on Babel if i'm not using npm? I'm write my own server on Golang and serving html and js files.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TODO APP</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script type='text/babel' src="./js/App.js"></script>
<script type='text/babel' src="./js/Info.js"></script>
</body>
</html>
App.js
class App extends React.Component {
render(){
return(
<div>
<span onClick={() => {alert('clicked')}}>{Date.now().toString()}</span>
<Info />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
Info.js
export default class Info extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: true,
};
this.handleClick = this.handleClick.bind(this);
}
render() {
const text = <label htmlFor="new-text">{this.state.isOpen ? 'Open' : "Closed"}</label>
return (
<div>
<button onClick={this.handleClick}>
{text}
</button>
</div>
)
}
handleClick(e) {
this.setState({
isOpen: !this.state.isOpen,
})
}
}
So i didn't know how to add Info to App. import didn't work cause i'm not using npm.
Import and export won't work. You need to add the script tags in proper order so that the dependencies are resolved.
index.html
<html>
<body>
<div id="app"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<!-- Order is important -->
<script src="/info.js" type="text/babel"></script>
<script src="/index.js" type="text/babel"></script>
</body>
</html>
info.js
class Info extends React.Component {
render(){
return(
<div>
Hello World Info
</div>
)
}
}
index.js
class App extends React.Component {
render(){
return(
<div>
Hello World
<Info/>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))

Calling a function in a file with jsx code in a js file

I have three files, percentGuageWidget.js, index.html, and main.js
percentGuageWidget.js has some react.js & jsx code
I am getting renderWidget is not defined. It seems if I call renderWidget in the percentGuageWidget.js, it works fine, but it won't work when called elsewhere.
How do I make it so I can call it from outside of that file.
class PercentGuageWidget extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0
}
}
componentDidMount() {
var widget = this;
setInterval(function(){
widget.setState({value:Math.round(Math.random()*100)});
}, 1000)
}
/* The render will be updated whenever state changes are made to the widget */
render() {
return (
<div className="percent-guage-widget widget">
<div className="bar" style={{width:this.state.value + "%"}}></div>
<div className="amount">{this.state.value}%</div>
</div>
);
}
}
var container = document.getElementById('target-widget-container');
function renderWidget(){
ReactDOM.render(<PercentGuageWidget />, container);
}
<html>
<head>
<script> var appGlobals = {} </script>
<script
src="http://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
crossorigin="anonymous"></script
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div id="target-widget-container"></div>
</body>
<script src="https://unpkg.com/react#15.0.1/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#15.0.1/dist/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script type="text/babel" src="widgets/percentGaugeWidget.js"></script>
<script>renderWidget();</script>
</html>

Resources