Exporting const from a fucntion in React into another component? - reactjs

I have a file ButtonExample.js that I am exporting a component (ButtonExample) and const (color) from. I am attempting to import them into a file called CustomCreation.js. However, on compiling I am met with the error:
Attempted import error: 'color' is not exported from './ButtonExample'.
This is the code for ButtonExample.js
import React, { useState } from "react";
import { GithubPicker } from "react-color";
function ButtonExample() {
const [showColorPicker, setShowColorPicker] = useState(false);
const [color, setColor] = useState("");
return (
<div>
<button
type="button"
class="btn btn-dark"
onClick={() =>
setShowColorPicker((showColorPicker) => !showColorPicker)
}
>
{showColorPicker ? "Close" : "Choose Color"}
</button>
{showColorPicker && (
<div>
<GithubPicker
color={color}
onChange={(updatedColor) => setColor(updatedColor.hex)}
colors={[
"#131313" /*black*/,
"#575757" /*grey*/,
"#f6f6f6" /*white*/,
"#203e20" /*green*/,
"#423122" /*brown*/,
"#121c4f" /*navy*/,
]}
/>
</div>
)}
</div>
);
}
export default { ButtonExample, color };
This is how I'm attempting to import it in CustomCreation.js
import ButtonExample, { color } from "./ButtonExample";
I've done this in the past and it's worked fine so I'm just unsure if I'm missing something really obvious.

color is declared as state inside the scope of the ButtonExample() functional component, so when you try to access it inside export default { ButtonExample, color }; it'll always be undefined.
Moreover, your export and import syntax seems incorrect. A default export defines a single export per module, so what you're essentially doing here is exporting an object comprised of ButtonExample and an undefined variable and attempting to use both named and default imports to import them.
To better share state between your components, you should either use a state manager like Redux to manage state globally throughout your application or implement a parent component for this component and any other component that relies on the current color. The parent component will then manage the color state and pass that down as a prop to any other components that need it. Additionally, the parent component will need to implement its own setColor function that it passes to ButtonExample as a prop, which can then be substituted for GithubPicker's onChange callback.

Related

Can anyone help me, I am stuck and can't figure the useRef Hook in React

Can someone explain to me if we can't create a reference in functional components, how is useRef creating a ref?
Take this code for example -
import "./styles.css";
import {useRef} from "react";
const App = () => {
const inputElement = useRef();
const focusInput = () => {
inputElement.current.focus();
};
return (
<>
<input type="text" ref={inputElement} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
export default App;
In class based components, refs are created using React.createRef() in the constructor. (See https://reactjs.org/docs/react-api.html#reactcreateref)
The constructor is executed only once at the start. When the component is rendered / updated as necessary multiple times, the render method is executed for each render.
However in function components, the component is the render method. So, to avoid creating a ref during each render, the useRef reusues the ref, which was created once. (See https://reactjs.org/docs/hooks-reference.html#useref)
The returned object will persist for the full lifetime of the component.

Extending component class exported wrapped in a HOC

This question had something to do with react-admin until I realized the problem was the was the component I was extending was actually exported.
I'm using a react-admin's TabbedForm and child FormTab to show lots of fields in my admin, and I need to customize a tab's layout.
Basically I want to extend FormTab with a custom layout.
But I'm not getting anywhere.
Here is the problem :
If I use a custom component for my tabs like
import React from 'react';
import {
FormTab,
FormInput,
} from 'react-admin'
const hiddenStyle = { display: 'none' };
export class CustomFormTab extends FormTab {
renderContent = ({ children, hidden, ...inputProps }) => (
<span style={hidden ? hiddenStyle : null}>
{React.Children.map(
children,
child => React.cloneElement(child, {
...inputProps
})
)}
</span>
);
}
export const CustomFormTabPart = ({ children, className, ...inputProps }) => {
return (
<div className={className}>
{React.Children.map(
children,
input =>
input && (
<FormInput
{...inputProps}
input={input}
/>
)
)}
</div>
)
}
This should get me going but I'm extending FormTab which not exported as a simple component.
// in react-admin/packages/ra-ui-materialui/src/form/FormTab.js
...
FormTab.displayName = 'FormTab';
export default translate(FormTab);
translate is a HOC...
I don't know how to extend this. Is that even possible ?
Actually the code in FormTab is not huge and copy-pasting it is a solution. I just hate like it.
It's a good practice to export original class as named export along with default export but this wasn't done in FormTab module.
It's a good practice to expose wrapped component (as can be seen in React Router's withRouter, React Redux's connect and so on) as static property on decorated component but this wasn't done in translate HOC.
Since translate wraps original FormTab component with context component, a quick-and-dirty fix is to deconstruct a hierarchy of React components:
const translateContext = FormTab.prototype.render();
const callback = translateContext.props.children;
const OriginalFormTab = callback({ translate: () => {}, label: '' }).type;
#translate
export class CustomFormTab extends OriginalFormTab { ... }
Since this is a hack that relies on third-party library internals, it may become broken with new library release, so it cannot be recommended, or at least requires to write unit test that tests internals in use.
A more appropriate solution is to fork a library, fix the drawbacks that were described (expose wrapped component in translate or/and export original components from modules) and submit a PR.

React.js - how to pass event handlers to deeply nested component without props drilling?

I have the structure of components (nested) that seems like this:
Container
ComponentA
ComponentB
ComponentC(want to handle event here with state that lives on container)
Do I need to pass as props all the way from Container, ComponentA, ComponentB and finally ComponentC to have this handler? Or is there another way like using Context API?
I'm finding a bit hard to handle events with react.js vs vue.js/angular.js because of this.
I would recommend using either Context API (as you mentioned) or Higher Order Components (HoC)
Context Api is your data center. You put all the data and click events that your application needs here and then with "Consumer" method you fetch them in any component regardless of how nested it is. Here is a basic example:
context.js //in your src folder.
import React, { Component, createContext } from "react";
import { storeProducts } from "./data"; //imported the data from data.js
const ProductContext = createContext(); //created context object
class ProductProvider extends Component {
state = {
products: storeProducts,
};
render() {
return (
<ProductContext.Provider
//we pass the data via value prop. anything here is accessible
value={{
...this.state,
addToCart: this.addToCart //I wont use this in the example because it would
be very long code, I wanna show you that, we pass data and event handlers here!
}}
>
// allows all the components access the data provided here
{this.props.children},
</ProductContext.Provider>
);
}
}
const ProductConsumer = ProductContext.Consumer;
export { ProductProvider, ProductConsumer };
Now we set up our data center with .Consumer and .Provider methods so we can access
here via "ProductConsumer" in our components. Let's say you want to display all your products in your home page.
ProductList.js
import React, { Component } from "react";
import Product from "./Product";
import { ProductConsumer } from "../context";
class ProductList extends Component {
render() {
return (
<React.Fragment>
<div className="container">
<div className="row">
<ProductConsumer>
//we fetch data here, pass the value as an argument of the function
{value => {
return value.products.map(product => {
return <Product key={product.id} />;
});
}}
</ProductConsumer>
</div>
</div>
</React.Fragment>
);
}
}
export default ProductList;
This is the logic behind the Context Api. It sounds scary but if you know the logic it is very simple. Instead of creating your data and events handlers inside of each component and prop drilling which is a big headache, just put data and your event handlers here and orchestrate them.
I hope it helps.

React. how to pass props from onClick to function

I am new to React, I am trying to create an app in which I can click on a button and a function will run countdown timer, but If I pass props from onClick to begin function like this, onClick={begin(props.subject)} the function will run before I click. and if I use onClick with begin without argument, there is no props being passed down. how can I fix that? thanks
import React from 'react';
import SubjectForm from './SubjectForm';
const EditSubject=(props)=>{
return(
<div>
<button onClick={begin}>start</button>
</div>)
};
const begin = (props)=> {
console.log(props.subject)
}
const mapStateToProps=()=>{};
export default connect(mapStateToProps)(EditSubject);
also, is there a way or trick to use a variable inside of begin function from an outside function? so I can make a pause button to pause seInterval in begin function.
You are using functional (stateless) components in this example. You can also use ES6 classes to represent React components, with functions being methods of the class. Then you may make functions like begin in your code as class methods, so they can access class data members like props.
See the code below:
import React from 'react';
import SubjectForm from './SubjectForm';
class EditSubject extends React.Component {
constructor() {
super();
this.begin = this.begin.bind(this);
}
begin() {
console.log(this.props.subject);
}
render() {
return (
<div>
<button onClick={begin}>start</button>
</div>
);
}
};
const mapStateToProps=()=>{};
export default connect(mapStateToProps)(EditSubject);
This is just a best practice if your component has states, and methods. Using functional components like in your example, you may use simply the following:
const EditSubject = (props) => {
return (
<div>
<button
onClick={() => begin(props)} // using props here
>
start
</button>
</div>
);
};
Simple, right ?

Passing Props between components

I am creating a bit of a playground to learn react and I've hit a road block with passing props between components. I essentially have two components, 1 that is the base component and then another that renders it out on the page with some extras (which i've removed for simplicity sake). I essentially want to be able to reuse the items in other places.
I'd like to be able to, when rendering the component in the example specify if it is type=submit if nothing specified default to type=button.
I'm clearly missing the point here because I get the error Cannot read property 'props' of undefined with the below code. Any help would be appreciated
Button Component
import React, {PropTypes} from 'react';
import './button_component.scss';
const propTypes = {
type: PropTypes.string
}
const ButtonComponent = () => {
return <button type={this.props.type}>button</button>
}
ButtonComponent.propTypes = propTypes;
export default ButtonComponent;
Then I have a component that outputs my item
import React from 'react';
import ButtonComponent from './button_component';
import Example from './example'
export default () =>
<Example>
<ButtonComponent type='button' />
</Example>;
ButtonComponent is a functional component. Hence, you can not use this.props in its code.
You should introduce props argument
const ButtonComponent = (props) => {
return <button type={props.type}>button</button>
}
Object destructuring and defaultProps can help you make your code simpler
const ButtonComponent = ({ type }) => {
return <button type={type}>button</button>
}
ButtonComponent.defaultProps = {
type: 'button'
}
then you can simply put <ButtonComponent /> to render a button.

Resources